詳細解讀JVM中的對象生命週期(2)

應用階段

當對象的創建階段結束之後,該對象通常就會進入對象的應用階段。這個階段是對象得以表現自身能力的階段。也就是說對象的應用階段是對象整個生命週期中證明自身“存在價值”的時期。在對象的應用階段,對象具備下列特徵:

◆系統至少維護着對象的一個強引用(Strong Reference);

◆所有對該對象的引用全部是強引用(除非我們顯式地使用了:軟引用(Soft Reference)、弱引用(Weak Reference)或虛引用(Phantom Reference))。

上面提到了幾種不同的引用類型。可能一些讀者對這幾種引用的概念還不是很清楚,下面分別對之加以介紹。在講解這幾種不同類型的引用之前,我們必須先了解一下Java中對象引用的結構層次。

Java對象引用的結構層次示意如圖2-6所示。

 

圖2-6  對象引用的結構層次示意

由圖2-6我們不難看出,上面所提到的幾種引用的層次關係,其中強引用處於頂端,而虛引用則處於底端。下面分別予以介紹。

1.強引用

強引用(Strong Reference)是指JVM內存管理器從根引用集合(Root Set)出發遍尋堆中所有到達對象的路徑。當到達某對象的任意路徑都不含有引用對象時,對這個對象的引用就被稱爲強引用。

2.軟引用

軟引用(Soft Reference)的主要特點是具有較強的引用功能。只有當內存不夠的時候,纔回收這類內存,因此在內存足夠的時候,它們通常不被回收。另外,這些引用對象還能保證在Java拋出OutOfMemory 異常之前,被設置爲null。它可以用於實現一些常用資源的緩存,實現Cache的功能,保證最大限度的使用內存而不引起OutOfMemory。再者,軟可到達對象的所有軟引用都要保證在虛擬機拋出OutOfMemoryError之前已經被清除。否則,清除軟引用的時間或者清除不同對象的一組此類引用的順序將不受任何約束。然而,虛擬機實現不鼓勵清除最近訪問或使用過的軟引用。下面是軟引用的實現代碼:

… … 
import java.lang.ref.SoftReference; 
… 
A a = new A(); 
… 
// 使用 a 
… 
// 使用完了a,將它設置爲soft 引用類型,並且釋放強引用; 
SoftReference sr = new SoftReference(a); 
a = null; 
… 
// 下次使用時 
if (sr!=null) { 
     a = sr.get(); 
} 
else{ 
     // GC由於內存資源不足,可能系統已回收了a的軟引用, 
     // 因此需要重新裝載。 
     a = new A(); 
     sr=new SoftReference(a); 
} 
… … 

軟引用技術的引進,使Java應用可以更好地管理內存,穩定系統,防止系統內存溢出,避免系統崩潰(crash)。因此在處理一些佔用內存較大而且聲明週期較長,但使用並不頻繁的對象時應儘量應用該技術。正像上面的代碼一樣,我們可以在對象被回收之後重新創建(這裏是指那些沒有保留運行過程中狀態的對象),提高應用對內存的使用效率,提高系統穩定性。但事物總是帶有兩面性的,有利亦有弊。在某些時候對軟引用的使用會降低應用的運行效率與性能,例如:應用軟引用的對象的初始化過程較爲耗時,或者對象的狀態在程序的運行過程中發生了變化,都會給重新創建對象與初始化對象帶來不同程度的麻煩,有些時候我們要權衡利弊擇時應用。

3.弱引用

弱引用(Weak Reference)對象與Soft引用對象的最大不同就在於:GC在進行回收時,需要通過算法檢查是否回收Soft引用對象,而對於Weak引用對象, GC總是進行回收。因此Weak引用對象會更容易、更快被GC回收。雖然,GC在運行時一定回收Weak引用對象,但是複雜關係的Weak對象羣常常需要好幾次GC的運行才能完成。Weak引用對象常常用於Map數據結構中,引用佔用內存空間較大的對象,一旦該對象的強引用爲null時,對這個對象引用就不存在了,GC能夠快速地回收該對象空間。與軟引用類似我們也可以給出相應的應用代碼:

… … 
import java.lang.ref.WeakReference; 
… 
A a = new A(); 
… 
// 使用 a 
… 
// 使用完了a,將它設置爲weak 引用類型,並且釋放強引用; 
WeakReference wr = new WeakReference (a); 
a = null; 
… 
// 下次使用時 
if (wr!=null) { 
    a = wr.get(); 
} 
else{ 
    a = new A(); 
    wr = new WeakReference (a); 
} 
… … 

弱引用技術主要適用於實現無法防止其鍵(或值)被回收的規範化映射。另外,弱引用分爲“短弱引用(Short Week Reference)”和“長弱引用(Long Week Reference)”,其區別是長弱引用在對象的Finalize方法被GC調用後依然追蹤對象。基於安全考慮,不推薦使用長弱引用。因此建議使用下面的方式創建對象的弱引用。

… … 
WeakReference wr = new WeakReference(obj); 
或 
WeakReference wr = new WeakReference(obj, false); 
… … 

4.虛引用

虛引用(Phantom Reference)的用途較少,主要用於輔助finalize函數的使用。Phantom對象指一些執行完了finalize函數,並且爲不可達對象,但是還沒有被GC回收的對象。這種對象可以輔助finalize進行一些後期的回收工作,我們通過覆蓋Reference的clear()方法,增強資源回收機制的靈活性。虛引用主要適用於以某種比 java 終結機制更靈活的方式調度 pre-mortem 清除操作。

&注意  在實際程序設計中一般很少使用弱引用與虛引用,使用軟引用的情況較多,這是因爲軟引用可以加速JVM對垃圾內存的回收速度,可以維護系統的運行安全,防止內存溢出(OutOfMemory)等問題的產生。

不可視階段

在一個對象經歷了應用階段之後,那麼該對象便處於不可視階段,說明我們在其他區域的代碼中已經不可以再引用它,其強引用已經消失,例如,本地變量超出了其可視範圍,如下所示。

… … 
public void process () { 
    try { 
         Object obj = new Object(); 
         obj.doSomething(); 
     } catch (Exception e) { 
     e.printStackTrace(); 
     } 
     while (isLoop) { // ... loops forever 
      // 這個區域對於obj對象來說已經是不可視的了 
         // 因此下面的代碼在編譯時會引發錯誤 
         obj.doSomething();  
     } 
} 
… … 

如果一個對象已使用完,而且在其可視區域不再使用,此時應該主動將其設置爲空(null)。可以在上面的代碼行obj.doSomething();下添加代碼行obj = null;,這樣一行代碼強制將obj對象置爲空值。這樣做的意義是,可以幫助JVM及時地發現這個垃圾對象,並且可以及時地回收該對象所佔用的系統資源。

不可到達階段

處於不可到達階段的對象,在虛擬機所管理的對象引用根集合中再也找不到直接或間接的強引用,這些對象通常是指所有線程棧中的臨時變量,所有已裝載的類的靜態變量或者對本地代碼接口(JNI)的引用。這些對象都是要被垃圾回收器回收的預備對象,但此時該對象並不能被垃圾回收器直接回收。其實所有垃圾回收算法所面臨的問題是相同的——找出由分配器分配的,但是用戶程序不可到達的內存塊。

可收集階段、終結階段與釋放階段

對象生命週期的最後一個階段是可收集階段、終結階段與釋放階段。當對象處於這個階段的時候,可能處於下面三種情況:

(1)垃圾回收器發現該對象已經不可到達。

(2)finalize方法已經被執行。

(3)對象空間已被重用。

當對象處於上面的三種情況時,該對象就處於可收集階段、終結階段與釋放階段了。虛擬機就可以直接將該對象回收了。

發佈了17 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章