1. 程式人生 > >jvm如何判斷物件已死?

jvm如何判斷物件已死?

在java的垃圾回收中,jvm是如何判斷堆中的物件是否已死呢?主流的判斷方法有兩種。 

1.引用計數演算法: 
  這種演算法的思路是如果某一個物件被別的物件引用,那麼就把他們引用計數器加上1,這樣當進行垃圾回收時如何判斷該引用的數量為0,此時就代表沒有進行任何物件對其進行引用,這種方法判斷效率很高,在很多情況下是個不錯的選擇,例如微軟的COM,AS3的FlashPlayer,Python語言等都是採用引用計數器進行判斷的,java沒有采用此 用法的原因是他無法解決迴圈引用的問題。 
eg : 
public class RefernceCountGC{ 
   public static instance = null; 


   public static final int _1MB = 1024 * 1024 ; 

   private byte[] bigSize = new byte[2 * _1MB]; 
   public static void testGC(){ 
      RefernceCountGC  objA = new RefernceCountGC(); 
      RefernceCountGC  objB = new RefernceCountGC(); 

     objA.instance= objB ; 
     objB.instance = objA ; 
     objA = null; 

     objB = null ; 
     System.gc(); 
  } 

上面的兩個物件objA和objB相互引用,如果用計算器演算法的話會導致無法進行回收。 

2.根搜尋演算法: 
   主流的語言Java,C#甚至古老的語言Lisp都是採用根搜尋演算法進行垃圾回收的,這個演算法的思路就是通過命名一系列的“GC Root"作為起點,從這些起點開始向下搜尋,這樣可以形成一條引用鏈,該引用鏈之外的物件都將被回收,在java鍾只有一下的物件才可以被作為GC Root. 
1>虛擬機器棧(棧幀中的本地方法表)中引用的物件。 
2>方法區中類靜態屬性引用的物件。 
3>方法區中常量引用的物件。 

4>本地方法棧JNI(即一般說的Native方法)的引用物件。 
3.關於引用: 
  在jdk1.2之前,java中的引用時這樣定義的:如果reference型別的資料中儲存的是另一塊記憶體的起始地址,就稱這塊記憶體代表著一個引用。這樣定義過於狹隘,因為這是一個物件只有引用和被引用兩種狀態,描述一下"食之無味,棄之可惜"的物件則無能無力,我們希望描述這樣的一類物件,當記憶體空間還夠是,則能留在記憶體中,否則記憶體進行垃圾回收後還緊張,那麼可以拋棄這些物件,jdk1.2後對引用進行了擴充,分為:強引用(Strong Reference),軟引用(Soft Reference),弱引用(Weak Reference),虛引用(Phantom Reference)四種。 
  3.1 強引用。 
   該引用是程式碼中普通存在的,例如Object objA = new Object(),只要強引用存在,垃圾收集器永遠不會回收掉被引用的物件。 
  3.2 軟引用。 
  該引用用來描述一些還有用,但是並非必須得物件,在系統將要爆發記憶體溢位之前,將會把這些物件列在進行回收的範圍之內,進行二次回收後如果還是記憶體不足,這時候才跑出記憶體溢位的錯誤。 
  3.3 若引用。 
   該引用也是用來描述非必須物件的,強度比軟引用更弱被若引用引用的物件只能存活到下一次垃圾回收之前。 
  3.4 虛引用也稱為幻影引用。 
  是最弱的一種的引用,一個物件是否存活與其生存週期沒有什麼影響,設定該引用的目的僅僅 是希望這個物件被釋放的時候能夠收到一個系統通知。 

4.生存還是死亡? 
  如果進行垃圾回收的時候發現一個物件沒有在GC Root鏈上,那麼就需要進行兩次的標記過程,如果當前發現沒有關聯在GC Root鏈上,那麼就會進行第一次標記,如果此時物件的finalize()方法沒有被覆蓋或該方法已經被虛擬機器呼叫過,那麼此時將被標記為沒有必要執行,此時該物件會被放入”即將回收“集合,否則就會放入F-Queue的物件中等待執行finalize()方法,如果在此方法中物件將自己與GC Root鏈上的任何一個物件關聯,那麼就會被溢位”即將回收“集合。

轉自:http://boyseegirl.iteye.com/blog/1684169