判斷Java對象是否存活的算法

聲明:本文摘抄自《深入理解Java虛擬機(jī)》一書,本文完全為自我學(xué)習(xí),請感興趣的同學(xué)購買正版,支持原創(chuàng)

判斷對象是否存活的算法包括:

  1. 引用計數(shù)算法
  2. 可達(dá)性分析算法

引用計數(shù)算法(Reference Counting)

給對象中添加一個引用計數(shù)器,每當(dāng)有一個地方引用它時,計數(shù)器加1;當(dāng)引用失效時,計數(shù)器值減1;任何時刻計數(shù)器為0的對象就是不能再被引用的。例如Object-C,Python語音使用引用計數(shù)算法進(jìn)行內(nèi)存管理。Java虛擬機(jī)沒有選用引用計數(shù)器算法來管理內(nèi)存,其中最主要的原有是它很難解決對象之間相互循環(huán)引用的問題。

對象循環(huán)引用代碼示例:

public class ReferenceCountingGC {
    public Object instance = null;
    
    public static void testGC() {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;
        
        objA = null;
        objB = null;
        
        // 假設(shè)在這行發(fā)生GC, objA 和 objB是否能被回收?
        System.gc();
    }
}

對象objA和objB都有字段instance,賦值令 objA.instance = objB及objB.instance = objA,除此之外,這兩個對象再無任務(wù)引用,實(shí)際上這兩個對象已經(jīng)不可能再被訪問,但是它們因?yàn)橄嗷ヒ弥鴮Ψ?,?dǎo)致它們的引用計數(shù)都不為0,于是引用計數(shù)算法無法通知GC收集器回收它們。

可達(dá)性分析算法(Reachability Analysis)

可達(dá)性分析算法的基本思路是通過一系列的稱為“GC Roots”的對象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain),當(dāng)一個對象到GC Root沒有任何引用鏈相連時,則證明此對象是不可用的。

左側(cè)為仍然存活的對象,右側(cè)為可回收的對象

生成還是死亡

即使在可達(dá)性分析算法中不可達(dá)的對象,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段,要真正宣告一個對象死亡,至少要經(jīng)歷兩次標(biāo)記過程:如果對象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用,那它將會被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是此對象是否是否有必要執(zhí)行finalize()方法。當(dāng)對象沒有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過,虛擬機(jī)將這兩種情況都視為“沒有必要執(zhí)行”。
??如果這個對象被判定為有必要執(zhí)行finalize()方法,那么這個對象將會放置在一個叫做F-Queue的隊列之中。并在稍后由一個虛擬機(jī)自動建立的,低優(yōu)先級的Finalizer線程去執(zhí)行它。這里所謂“執(zhí)行”是指虛擬機(jī)會觸發(fā)這個方法,但并不承諾會等待它運(yùn)行結(jié)束,這樣做的原有是,如果有一個對象在finalize()方法中執(zhí)行緩慢,或者發(fā)生死循環(huán),將可能會導(dǎo)致F-Queue隊列中其他對象永久處于等待,甚至導(dǎo)致整個內(nèi)存回收系統(tǒng)崩潰。
??finalize()方法是對象逃脫死亡命運(yùn)的最后一次機(jī)會,稍后GC將對F-Queue中的對象進(jìn)行第二次小規(guī)模的標(biāo)記,如果對象這個時候,未被重新引用,那它基本上就真的被回收了。

回收方法區(qū)

Java虛擬機(jī)規(guī)范中確實(shí)說過可以不要求虛擬機(jī)在方法區(qū)中實(shí)現(xiàn)垃圾回收,而且在方法區(qū)中進(jìn)行垃圾回收的“性價比”一般比較低,方法區(qū)的垃圾收集主要回收兩部分內(nèi)容:廢棄的常量和無用的類。

廢棄的常量,以常量池中字面量的回收為例,假如一個字符串“abc”已經(jīng)進(jìn)入常量池中,但是當(dāng)前系統(tǒng)已經(jīng)沒有任何一個String對象叫做“abc”的,也沒有任何其他地方引用這個字面量,這個“abc”常量就會被清理出常量池。

判斷一個無用的類需要同時滿足下面3個條件才能算是“無用的類”

  • 該類的所有實(shí)例都已經(jīng)被回收
  • 加載該類的ClassLoader已經(jīng)被回收
  • 該類對應(yīng)的java.lang.Class對象已經(jīng)沒有任何地方被引用,無法在任何地方通過反射訪問該類的方法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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