一個(gè)對(duì)象什么時(shí)候才能被回收?

目錄:

1、怎樣判斷一個(gè)對(duì)象“已死”?
2、引用的分類
3、回收方法區(qū)的數(shù)據(jù)

1、怎樣判斷一個(gè)對(duì)象“已死”?

在堆里面存放著 Java 世界中幾乎所有的對(duì)象實(shí)例,垃圾收集器在對(duì)堆進(jìn)行回收前,第一件事情就是要確定這些對(duì)象之中哪些還“存活”著,哪些已經(jīng)“死去”(即不可能再被任何途徑使用的對(duì)象)。

那么怎么判斷一個(gè)對(duì)象“已死”呢,目前有兩種算法可以判斷對(duì)象“已死”。

  1. 引用計(jì)數(shù)算法:
    這個(gè)算法的判斷依據(jù)是通過給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加 1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減 1;任何時(shí)刻計(jì)數(shù)器為 0 的對(duì)象就不可能再被使用的。
    客觀的說,引用計(jì)數(shù)算法的實(shí)現(xiàn)簡單,判斷效率也很高,在大部分情況下它都是一個(gè)不錯(cuò)的算法,也有一些比較著名的應(yīng)用案例,例如微軟公司的 COM(Component Object Model)技術(shù)。但是,至少主流的 Java 虛擬機(jī)里面沒有選用引用計(jì)算法來管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問題。

    舉個(gè)簡單的例子,請(qǐng)看下面代碼中的 testGC() 方法:對(duì)象 objA 和 objB 都有字段 mInstance,賦值令 objA.mInstance = objB 及 objB.mInstance = objA,除此之外,這兩個(gè)對(duì)象再無任何實(shí)際上這兩個(gè)對(duì)象已經(jīng)不可能再被訪問,但是它們因?yàn)榛ハ嘁弥鴮?duì)方,導(dǎo)致它們的引用計(jì)數(shù)都不為 0,于是引用技術(shù)算法無法通知 GC 收集器回收它們。
    對(duì)象不存在時(shí)引用計(jì)數(shù)器不為 0 的情況
  2. 可達(dá)性分析算法:

    在主流的商用程序語言(如Java)的主流實(shí)現(xiàn)中,都是稱通過可達(dá)性分析來判斷對(duì)象是否存活的。這個(gè)算法的基本思路就是通過一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到 GC Roots 沒有任何引用鏈相連時(shí),則證明此對(duì)象是不可用的。
    可達(dá)性分析算法判定對(duì)象是否可回收

    在 Java 語言中,可作為 GC Roots 的對(duì)象包括下面幾種:
  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象。
  • 方法區(qū)中常量引用的對(duì)象。
  • 本地方法棧中 JNI(即一般說的 Native 方法)引用的對(duì)象。

2、引用的分類

無論是通過引用計(jì)數(shù)算法判斷對(duì)象的引用數(shù)量,還是通過可達(dá)性分析判斷對(duì)象的引用鏈?zhǔn)欠窨蛇_(dá),判斷對(duì)象是否存活都與“引用”有關(guān)。

在 JDK 1.2 之后,Java 對(duì)引用的概念進(jìn)行了擴(kuò)充,將引用分為強(qiáng)引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference) 4 種,這 4 種引用強(qiáng)度一次逐漸減弱。

  • 強(qiáng)引用就是指在程序代碼之中普遍存在的,只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
  • 軟引用是用來描述一些還有用但并非必須的對(duì)象。對(duì)于軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前(即內(nèi)存緊張), 將會(huì)把這些對(duì)象列進(jìn)垃圾回收范圍之中進(jìn)行第二次回收。如果這次回收還沒有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。在 JDK1.2 之后, 提供了 SoftReference 類累實(shí)現(xiàn)軟引用。
  • 弱引用是用來描述非必需的對(duì)象的,但是它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。 當(dāng)垃圾收集器工作時(shí),無論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。使用 WeekReference 類來實(shí)現(xiàn)弱引用。
  • 虛引用也成為幽靈引用或者幻影引用,它是最弱的一種引用。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存周期時(shí)間構(gòu)成影響, 也無法通過虛引用來取得一個(gè)對(duì)象實(shí)例。唯一的作用就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。使用 PhantomReference 表示。

3、回收方法區(qū)數(shù)據(jù)

方法區(qū)的垃圾收集主要回收兩部分內(nèi)容:廢棄常量和無用的類?;厥諒U棄常量與回收 Java 堆中的對(duì)象非常類似。以常量池中字面量的回收為例,假如一個(gè)字符串“abc”已經(jīng)進(jìn)入了常量池,但是當(dāng)前系統(tǒng)沒有任何一個(gè) String 對(duì)象是叫做 “abc”的,換句話說,就是沒有任何一個(gè) String 對(duì)象引用常量池中的“abc”常量,也沒有其他地方引用了這個(gè)字面量,如果這時(shí)發(fā)生內(nèi)存回收,而且必要的話,這個(gè)“abc”常量就會(huì)被系統(tǒng)清理出常量池。常量池中的其他類(接口)、方法、字段的符號(hào)引用也與此類似。

判定一個(gè)常量為“廢棄常量”比較簡單,而要判斷一個(gè)常量池中的類是否是“無用的類”條件則苛刻很多。類需要同時(shí)滿足下面 3 個(gè)條件才能稱為“無用的類”:

  • 該類所有的實(shí)例都已經(jīng)被全部回收,也就是說 Java 堆中不再存在任何該類的實(shí)例。
  • 加載該類的 ClassLoader 已經(jīng)被回收。
  • 該類對(duì)應(yīng)的 java.lang.Class 對(duì)象沒有在任何地方引用,并且無法再任何地方通過反射調(diào)用該類的方法。

最后做個(gè)總結(jié):

  1. 我們可以通過 引用計(jì)數(shù)器 和 可達(dá)性算法 來判斷一個(gè)對(duì)象是否“已死”。引用計(jì)數(shù)器很難解決對(duì)象之間互相循環(huán)引用的問題,所以在主流的商用程序語言(如Java)的主流實(shí)現(xiàn)中,都是稱通過可達(dá)性分析來判斷對(duì)象是否存活的。
  2. 對(duì)象的引用可以分為 強(qiáng)引用、軟引用、弱引用 以及 虛引用 4 種,其中被 強(qiáng)引用 引用的對(duì)象垃圾收集器永遠(yuǎn)不會(huì)回收掉;被 軟引用 引用的對(duì)象,只有當(dāng)系統(tǒng)將要發(fā)生內(nèi)存溢出時(shí),才會(huì)去回收軟引用引用的對(duì)象;只被 弱引用關(guān)聯(lián)的對(duì)象,只要發(fā)生垃圾收集事件,只被弱引用關(guān)聯(lián)的對(duì)象就會(huì)被回收;被虛引用關(guān)聯(lián)的對(duì)象的唯一作用是能在這個(gè)對(duì)象被回收器回收時(shí)受到一個(gè)系統(tǒng)通知。
  3. 回收方法區(qū)的數(shù)據(jù),垃圾收集器主要回收 廢棄常量和無用的類 兩部分內(nèi)容。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.什么是垃圾回收? 垃圾回收(Garbage Collection)是Java虛擬機(jī)(JVM)垃圾回收器提供...
    簡欲明心閱讀 90,394評(píng)論 17 311
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡(luò)上收集的一些資料的整理,因此不免有一些不準(zhǔn)確的地方,同時(shí)不同JDK版本的...
    高廣超閱讀 16,074評(píng)論 3 83
  • 《深入理解Java虛擬機(jī)》筆記_第一遍 先取看完這本書(JVM)后必須掌握的部分。 第一部分 走近 Java 從傳...
    xiaogmail閱讀 5,484評(píng)論 1 34
  • JVM內(nèi)存區(qū)域 JVM將其管理的內(nèi)存分為若干數(shù)據(jù)區(qū)域,這些數(shù)據(jù)區(qū)域分布情況如下圖所示: 程序計(jì)數(shù)器:一塊較小內(nèi)存區(qū)...
    luoxn28閱讀 784評(píng)論 0 0
  • 1、感恩健康的犒賞讓我存活于世,謝謝,謝謝,謝謝! 2、感恩金錢滋養(yǎng)我的生活,謝謝,謝謝,謝謝! 3、感恩按摩師給...
    天空云閱讀 382評(píng)論 0 0

友情鏈接更多精彩內(nèi)容