最近GC相關的資料,看到一些好玩的東西,在些總結一下!
代碼清單1-1
public static void main(String[] args){
byte[] placeholder = new byte[64*1024*1024];
System.gc();
}
代碼清單1-1中的代碼很簡單,即向內存填充了64MB的數據,然後通知虛擬機進行垃圾收集。我們在虛擬機運行參數中加上“-verbose:gc” 來看看垃圾收集的過程,發現在System.gc()運行後並沒有回收這64MB的內存,下面是運行的結果:
[GC 68157K->66120K(249344K), 0.0009462 secs]
[Full GC 66120K->66000K(249344K), 0.0088075 secs]
說明:沒有回收placeholder所佔的內存能說得過去,因爲在執行System.gc()時,變量placeholder 還處於作用域內,虛擬機自然不敢回收placeholder的內存。
把代碼修改一下,變成代碼清單1-2
代碼清單1-2
public static void main(String[] args){
byte[] placeholder = new byte[64*1024*1024];
placeholder = null;
System.gc();
}
代碼清單1-2中,手動把大對象placeholder置爲null,運行結果爲:[GC 68157K->66072K(249344K), 0.0032981 secs]
[Full GC 66072K->464K(249344K), 0.0163352 secs]
說明:從運行結果可以看出來,placeholder對象的內存被回收掉了!
把代碼修改一下,變成代碼清單1-3
代碼清單1-3
public static void main(String[] args){
{
byte[] placeholder = new byte[64*1024*1024];
}
System.gc();
}
加了花括號之後,placeholder的作用域被限定在花括號之內,從代碼邏輯上講,在執行System.gc()的時候,placeholder已經不可能再被訪問了,但執行一下這段程序 ,會發現運行結果如下,還是64MB的內存沒有被回收,這又是爲什麼呢?[GC 68157K->66104K(249344K), 0.0009837 secs]
[Full GC 66104K->66000K(249344K), 0.0078921 secs]
在解析爲什麼之前,我們先對這段代碼再進行修改,在調用System.gc()之前加入一行“int a=0;”,變成代碼清單1-4的樣子:
代碼清單1-4
public static void main(String[] args){
{
byte[] placeholder = new byte[64*1024*1024];
}
int a = 0;
System.gc();
}
這個修改看起來很莫名奇妙,但運行一下程序,卻發現這次內存真的被回收了。
[GC 68157K->66104K(249344K), 0.0008698 secs]
[Full GC 66104K->464K(249344K), 0.0087568 secs]
在代碼清單1-1中,代碼雖然已經離開了placeholder的作用域,但在此之後,沒有任何對局部變量表的讀寫操作placeholder原本所佔用的Slot還沒有被其他變量所複用,所以GC Root一部分的局部變量表仍然保持着對它的關聯。這種關聯沒有被及時打斷,在絕大部分情況下影響都很輕微。但如果遇到一個方法,其後面的代碼有一些耗時很長的操作,而前面又定義了佔用了大量的內存、實際上已經不再使用的變量,那問題就被放大,解決方法就是如代碼清單1-2手動將其設置爲null值或如代碼清單1-4用int a=0把變量對應的局部變量表Slot清空。
代碼清單1-5
public static void main(String[] args){
foo();
System.gc();
}
public static void foo(){
byte[] placeholder = new byte[64*1024*1024];
}
代碼清單1-5的運行結果:
[GC 68157K->66120K(249344K), 0.0011992 secs]
[Full GC 66120K->464K(249344K), 0.0084784 secs]
可以看到64M的內存已經被回收,placeholder是foo方法的局部變量,在main方法中調用的時候,其實foo方法對應的棧幀已經結束.那麼placeholder指向的大對象自然被gc的時候回收了.