天天看點

深入了解Java虛拟機筆記---引用類型和對象是否死亡

   在JDK1.2以前,Java中的引用定義得很傳統:如果reference類型的數值代表的是另外一塊記憶體的起始位址,就稱這塊記憶體代表中一個引用。這種定義很純粹,但太過狹隘,一個對象在這種定義下隻有被引用或者沒有引用兩種狀态,對于如何描述一個“食之無味,棄之可惜”的對象就顯得無能為力;如果記憶體在進行垃圾收集後還是非常緊張,則可以抛棄這些對象。很多系統的緩存功能都符合這樣的應用場景。

   在JDK1.2之後,Java對引用的概念進行了擴充,将引用分為強引用(Strong Reference),軟引用(Soft Reference),弱引用(Weak Reference),虛引用(Phantom Reference)四種,這四種引用強度依賴逐漸減弱。

1.強引用就是指在程式代碼之中普遍存在的,類似“Object obj = new Object()”這類引用,隻要強引用存在,垃圾收集器永遠不會回收掉被引用的對象。

2.軟引用用來描述一些還有用,但并非必須的對象。對于軟引用關聯着的對象,在系統将要發生記憶體溢出之前,将會把這些對象列進回收範圍之中,并進行第二次回收。如果這次回收還是沒有足夠的記憶體,才會抛出記憶體溢出錯誤。在JDK1.2之後,提供了SoftReference來實作軟引用。

3.弱引用也是用來描述非必須對象的,但是它的強度比軟引用更弱一點,被弱引用關聯的對象隻能生存到下一次垃圾回收之前。當垃圾收集器工作時,無論目前記憶體是否足夠,都會回收掉被弱引用關聯的對象。在JDK1.2之後,提供了WeakReference來實作弱引用。

4.虛引用它是最弱的一種引用關系。一個對象是否有虛引用存在,完全不會對其生存時間構成影響,也無法通過虛引用來取得一個對象的執行個體。為一個對象設定虛引用關聯的唯一目的是希望能在這個對象被收集器回收時收到一個系統通知。在JDK1.2之後,提供了PhantomReference來實作虛引用。

   在根搜尋算法中不可達的對象,也并非是“非死不可的”,這時候它們暫時處于“緩刑”階段,要真正宣告一個對象死亡,至少要經曆兩次标記過程:如果對象在進行根搜尋後發現沒有與GC Roots相連接配接的引用鍊,那它将會被第一次标記并進行一次篩選,篩選的條件是此對象是否有必要執行finalize()方法。當對象沒有覆寫finallize()方法或該對象的finalize()已經被調用過,虛拟機将這兩種情況都視為“沒有必要執行”。

   如果一個對象被判斷為有必要執行finalize()方法,那麼這個對象将會被放置在一個名為F-Queue的隊列之中,并在稍後由一條虛拟機自動建立的,低優先級的Finalizer線程去執行。這裡所謂的“執行”是指虛拟機會觸發這個方法,但并不承諾會等待它運作結束。這樣做的原因是,如果一個對象在fianlize()方法中執行緩慢,或者發生了死循環,将很可能會導緻F-Queue隊列中的其它對象永久處于等待狀态,甚至導緻整個記憶體回收系統崩潰。finalize()方法是對象逃脫死亡命運的最後一次機會,稍後GC将對F-Queue中的對象進行第二次小規模的标記,如果對象在finalize()中成功拯救自己--隻要重新與引用鍊上的任何一個對象建立關聯既可,那在第二次标記時它将被移出“即将回收”集合;如果對象這時候還沒有逃脫,那它就将被回收了。