JVM 引用計數法 & 引用鏈法詳細解析:如何判斷一個Java對象是否存活

前言

  • 如何判斷一個Java對象是否存活對於垃圾回收、防止內存泄漏等十分重要
  • 本文將全面講解判斷Java對象存活的方式,希望你們會喜歡

目錄

示意圖


1. 判斷方式

  • 垃圾收集器對 Java堆裏的對象 是否進行回收的判斷準則:Java對象是存活 or 死亡

判斷對象爲死亡纔會進行回收

  • Java虛擬機中,判斷對象是否存活有2種方法:
    1. 引用計數法
    2. 引用鏈法(可達性分析法)

下面會進行詳細介紹。


2. 引用計數法

2.1 方式描述

  • Java 對象添加一個引用計數器
  • 每當有一個地方引用它時,計數器 +1;引用失效則 -1;

2.2 判斷對象存活準則

當計數器不爲 0 時,判斷該對象存活;否則判斷爲死亡(計數器 = 0)。

2.3 優點

  • 實現簡單
  • 判斷高效

2.4 缺點

  • 無法解決 對象間相互循環引用 的問題

即該算法存在判斷邏輯的漏洞

  • 具體描述
<-- 背景 -->
// 對象objA 和 objB 都有字段 name
// 兩個對象相互進行引用,除此之外這兩個人對象沒有任何引用
objA.name = objB;
objB.name = objA;

<-- 問題 -->
// 實際上這兩個對象已經不可能再被訪問,應該要被垃圾收集器進行回收
// 但因爲他們相互引用,所以導致計數器不爲0,這導致引用計數算法無法通知垃圾收集器回收該兩個對象

正由於該算法存在判斷邏輯漏洞,所以 Java虛擬機沒有采用該算法判斷Java是否存活。


3. 引用鏈法(可達性分析法)

  • 很多主流商用語言(如JavaC#)都採用 引用鏈法 判斷 Java對象是否存活。
  • 含3個步驟:
    1. 可達性分析
    2. 第一次標記 & 篩選
    3. 第二次標記 & 篩選

3.1 可達性分析

a. 方式描述

將一系列的 GC Roots 對象作爲起點,從這些起點開始向下搜索。

  • 可作爲 GC Root 的對象有:
    1.Java虛擬機棧(棧幀的本地變量表)中引用的對象
    2.本地方法棧 中 JNI引用對象
    3.方法區 中常量、類靜態屬性引用的對象
  • 向下搜索的路徑 = 引用鏈

如下圖:

示意圖

b. 判斷 對象是否可達 標準

當一個對象到 GC Roots 沒有任何引用鏈相連時,則判斷該對象不可達

沒有任何引用鏈相連 = GC Root到對象不可達 = 對象不可用

示意圖

特別注意

  • 可達性分析 僅僅只是判斷對象是否可達,但還不足以判斷對象是否存活 / 死亡
  • 當在 可達性分析 中判斷不可達的對象,只是“被判刑” = 還沒真正死亡

不可達對象會被放在”即將回收“的集合裏。

  • 要判斷一個對象真正死亡,還需要經歷兩個階段:
    1. 第一次標記 & 篩選
    2. 第二次標記 & 篩選

3.2 第一次標記 & 篩選

  • 對象 在 可達性分析中 被判斷爲不可達後,會被第一次標記 & 準備被篩選

a. 不篩選:繼續留在 ”即將回收“的集合裏,等待回收;
b. 篩選:從 ”即將回收“的集合取出

  • 篩選的標準:該對象是否有必要執行 finalize()方法
    1. 若有必要執行(人爲設置),則篩選出來,進入下一階段(第二次標記 & 篩選);
    2. 若沒必要執行,判斷該對象死亡,不篩選 並等待回收

當對象無 finalize()方法 或 finalize()已被虛擬機調用過,則視爲“沒必要執行”


3.3 第二次標記 & 篩選

當對象經過了第一次的標記 & 篩選,會被進行第二次標記 & 準備被進行 篩選

a. 方式描述

該對象會被放到一個 F-Queue 隊列中,並由 虛擬機自動建立、優先級低的Finalizer 線程去執行 隊列中該對象的finalize()

  1. finalize()只會被執行一次
  2. 但並不承諾等待finalize()運行結束。這是爲了防止 finalize()執行緩慢 / 停止 使得 F-Queue隊列其他對象永久等待。

b. 篩選標準

在執行finalize()過程中,若對象依然沒與引用鏈上的GC Roots 直接關聯 或 間接關聯(即關聯上與GC Roots 關聯的對象),那麼該對象將被判斷死亡,不篩選(留在”即將回收“集合裏) 並 等待回收


3.4 總結

3步驟 + 以下流程
示意圖


4. 總結

  • 本文全面講解判斷Java對象存活的方式
  • 在接下來的日子,我會推出一系列講解JVM的文章,具體如下;感興趣的同學可以繼續關注本人運營的:CSDN技術博客

示意圖


請幫頂 / 評論點贊!因爲你的鼓勵是我寫作的最大動力!

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