Java 中對象的生命週期與垃圾回收

文章轉自:耿玉龍

垃圾回收

垃圾回收是 Java 程序設計中內存管理的核心概念,JVM 的內存管理機制被稱爲垃圾回收機制。

一個對象創建後被放置在 JVM 的堆內存中,當永遠不再引用這個對象時,它將被 JVM 在堆內存中回收。被創建的對象不能再生,同時也沒有辦法通過程序語句釋放它們。即當對象在 JVM 運行空間中無法通過根集合到達(找到)時,這個對象被稱爲垃圾對象根集合是由類中的靜態引用域與本地引用域組成的。JVM 通過根集合索引對象。

在做Java應用開發時經常會用到由JVM管理的兩種類型的內存:堆內存棧內存

  • 堆內存
    堆內存在JVM啓動的時候被創建,堆內存中所存儲的對象可以被JVM自動回收,不能通過其他外部手段回收,也就是說開發人員無法通過添加相關代碼的手段來回收堆內存中的對象。堆內存通常情況下被分爲兩個區域:新對象區域與老對象區域。

    新對象區域:又可細分爲三個小區域:伊甸園區域、From區域與To區域。伊甸園區域用來保存新創建的對象,它就像一個堆棧,新的對象被創建,就像指向該棧的指針在增長一樣,當伊甸園區域中的對象滿了之後,JVM系統將要做到可達性測試,主要任務是檢測有哪些對象由根集合出發是不可達的,這些對象就可以被JVM回收,並且將所有的活動對象從伊甸園區域拷貝到To區域,此時一些對象將發生狀態交換,有的對象就從To區域被轉移到From區域,此時From區域就有了對象。上面對象遷移的整個過程,都是由JVM控制完成的。

    老對象區域:在老對象區域中的對象仍然會有一個較長的生命週期,大多數的JVM系統垃圾對象,都是源於”短命”對象,經過一段時間後,被轉入老對象區域的對象,就變成了垃圾對象。此時,它們都被打上相應的標記,JVM系統將會自動回收這些垃圾對象,建議不要頻繁地強制系統作垃圾回收,這是因爲JVM會利用有限的系統資源,優先完成垃圾回收工作,導致應用無法快速地響應來自用戶端的請求,這樣會影響系統的整體性能。

  • 棧內存
    堆內存主要用來存儲程序在運行時創建或實例化的對象與變量。例如通過new關鍵字創建的對象。而棧內存則是用來存儲程序代碼中聲明爲靜態或非靜態的方法。

JVM中對象的生命週期

在JVM運行空間中,對象的整個生命週期大致可以分爲7個階段:

  • 創建階段
  • 應用階段
  • 不可到達階段
  • 可收集階段
  • 終結階段
  • 釋放階段

這7個階段,構成了JVM中對象的完整的生命週期。
1. 創建階段

在對象的創建階段,系統主要通過下面的步驟,完成對象的創建過程:
- 爲對象分配存儲空間;
- 開始構造對象;
- 從超類到子類對static成員進行初始化;
- 超類成員變量按順序初始化,遞歸調用超類的構造方法;
- 子類成員變量按順序初始化,子類構造方法調用。

在創建對象時應注意幾個關鍵應用規則:
- 避免在循環體中創建對象,即使該對象佔用內存空間不大。
- 儘量及時使對象符合垃圾回收標準。比如 myObject = null。
- 不要採用過深的繼承層次。
- 訪問本地變量優於訪問類中的變量

2. 應用階段
在對象的引用階段,對象具備如下特徵:
1. 系統至少維護着對象的一個強引用(Strong Reference);
2. 所有對該對象的引用全部是強引用(除非我們顯示地適用了:軟引用(Soft Reference)、弱引用(Weak Reference)或虛引用(Phantom Reference)).

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

軟引用(Soft Reference):軟引用的主要特點是有較強的引用功能。只有當內存不夠的時候,纔回收這類內存,因此內存足夠時它們通常不被回收。另外這些引用對象還能保證在Java拋出OutOfMemory異常之前,被設置爲null。它可以用於實現一些常用資源的緩存,實現Cache功能,保證最大限度地使用內存你而不引起OutOfMemory。

// 軟引用應用演示代碼
public class Soft {

    public static void main(String[] args) {

        // create object
        Operation opr = new Operation();

        // do something
        opr.doSomething();

        // cache it
        SoftReference<Operation> soft = new SoftReference<>(opr);

        // release opr
        opr = null;

        // ...

        // next time
        if (soft == null) // GC reclaimed it, reload object
            soft = new SoftReference<>(new Operation());

        // get object
        Operation nextOpr = soft.get();

        // continue do something
        nextOpr.doSomething();

    }
}

軟引用技術的引進使Java應用可以更好地管理內存,穩定系統,防止系統內存溢出,避免系統崩潰。因此在處理一些佔用內存較大且生命週期較長,但使用並不繁地對象時應儘量應用該技術。提高系統穩定性。

弱引用(Weak Reference):弱應用對象與軟引用對象的最大不同就在於:GC在進行垃圾回收時,需要通過算法檢查是否回收Soft應用對象,而對於Weak引用,GC總是進行回收。Weak引用對象更容易、更快地被GC回收。Weak引用對象常常用於Map結構中。

// 弱引用應用演示代碼
public class Weak{

    public static void main(String[] args) {

        // create object
        Operation opr = new Operation();

        // do something
        opr.doSomething();

        // cache it
        WeakReference<Operation> weak= new WeakReference<>(opr);

        // release opr
        opr = null;

        // ...

        // next time
        if (weak== null) // GC reclaimed it, reload object
            weak= new WeakReference<>(new Operation());

        // get object
        Operation nextOpr = weak.get();

        // continue do something
        nextOpr.doSomething();

    }
}

虛引用(Phantom Reference): 虛引用的用途較少,主要用於輔助finalize函數的使用。
虛引用(Phantom Reference)對象指一些執行完了finalize函數,併爲不可達對象,但是還沒有被GC回收的對象。這種對象可以輔助finalize進行一些後期的回收工作,我們通過覆蓋了Refernce的clear()方法,增強資源回收機制的靈活性。

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

3. 不可視階段
當一個對象處於不可視階段,說明我們在其他區域的代碼中已經不可以在引用它,其強引用已經消失,例如,本地變量超出了其可視的範圍。

    try {   
        Object localObj = new Object();   
        localObj.doSomething();   
    } catch (Exception e) {   
        e.printStackTrace();   
    }   

    if (true) {   
       // 此區域中localObj 對象已經不可視了, 編譯器會報錯。   
       localObj.doSomething();   
    }  

4. 不可達階段
處於不可達階段的對象在虛擬機的對象引用根集合中再也找不到直接或間接地強引用,這些對象一般是所有線程棧中的臨時變量。所有已經裝載的靜態變量或者是對本地代碼接口的引用。

5. 可收集階段、終結階段與釋放階段
當一個對象處於可收集階段、終結階段與釋放階段時,該對象有如下三種情況:
1. 回收器發現該對象已經不可達。
2. finalize方法已經被執行。
3. 對象空間已被重用。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章