摘要:前言最近在看實戰(zhàn)虛擬機(jī)發(fā)現(xiàn)書上的一個關(guān)于局部變量表挺有意思,先上代碼。主角沒有分配了一塊的堆空間,并使用局部變量引用這塊空間然后顯式進(jìn)行一次。
前言
最近在看《實戰(zhàn)Java虛擬機(jī)》, 發(fā)現(xiàn)書上的一個關(guān)于局部變量表GC挺有意思,先上代碼。
主角 沒有GCpublic class Main { public static void reversion(){ { byte[] a = new byte[6*1024*1024]; } System.gc(); } public static void main(String[] args) { reversion(); } }
分配了一塊6MB的堆空間,并使用局部變量引用這塊空間, 然后顯式進(jìn)行一次Full GC。
先配置一下JVM參數(shù)用于打印GC log
可以看到這塊6MB的堆空間并沒有被回收, 接下來加一行代碼就能使得堆空間被回收。
可以GCpublic class Main { public static void reversion(){ { byte[] a = new byte[6*1024*1024]; } int c = 0; System.gc(); } public static void main(String[] args) { reversion(); } }
可以看到這6MB的空間已經(jīng)被回收了,僅僅因為多了一句看似與a毫無關(guān)系的 int c = 0;
答案借助jclasslib工具我們進(jìn)一步查看函數(shù)的局部變量信息, 在此之前我們需要對代碼做一點小改動再進(jìn)行分析
public class Main { public static void reversion(){ { byte[] a = new byte[6*1024*1024]; System.out.println(a[0]); } int c = 0; System.gc(); } public static void main(String[] args) { reversion(); } }
tips:JVM即時編譯器擁有死代碼消除的特性,a數(shù)組并沒有被任何地方使用,即時編譯器可以精簡數(shù)據(jù)流,并且減少編譯時間以及最終生成機(jī)器碼的大小。簡單的說如果a沒有被使用的話會被編譯成var0, 我們在本地變量表中看不到a了。
可以看到a和c在局部變量表中的索引值都是0,也就是說c重用了a在局部變量表中的槽位,從而使得a指向的堆空間能夠被GC回收
棧幀中的局部變量表中的槽位是可以重用的,如果一個局部變量過了其作用域,那么在其作用域之后申明的新的局部變量就很有可能復(fù)用過期局部變量的槽位,從而達(dá)到節(jié)省資源的目的
總結(jié)通過這個GC的小例子,切實感受到了JVM對于資源節(jié)省的嚴(yán)苛程度,對于作用域的細(xì)粒度把控之強(qiáng)大。給大家推薦我讀的這本《實戰(zhàn)Java虛擬機(jī)》,切實的一本好書,所謂好書無非兩點:1.能讀懂 2.有所獲。同時也推薦極客時間的《深入拆解虛擬機(jī)》,多路學(xué)習(xí),兼聽則明。
最后打個小廣告~
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/71928.html
摘要:垃圾回收及一次內(nèi)存泄漏處理內(nèi)存分布上圖展示了的架構(gòu)圖,本篇我們主要關(guān)注,運行時數(shù)據(jù)區(qū)。但是垃圾回收并不能百分百保證不會出現(xiàn)內(nèi)存泄漏,所以了解垃圾回收,對于我們遇到內(nèi)存泄漏時能更加清晰的分析原因,也能幫助我們寫出更加安全,可靠的程序。 [toc] JAVA GC垃圾回收(及一次內(nèi)存泄漏處理) showImg(https://segmentfault.com/img/remote/1460...
閱讀 2750·2021-11-25 09:43
閱讀 2111·2021-11-18 13:25
閱讀 4574·2021-09-22 15:52
閱讀 1870·2021-09-22 15:49
閱讀 2216·2019-08-30 15:54
閱讀 3011·2019-08-29 17:13
閱讀 2318·2019-08-29 16:54
閱讀 2259·2019-08-29 12:58