前言
- 如何判斷一個(gè)Java對(duì)象是否存活對(duì)于垃圾回收茁帽、防止內(nèi)存泄漏等十分重要
- 本文將全面講解判斷
Java
對(duì)象存活的方式饶唤,希望你們會(huì)喜歡
Carson帶你學(xué)JVM系列文章敏簿,具體如下:
Carson帶你學(xué)JVM:這是一份全面 & 詳細(xì)的JVM學(xué)習(xí)指南
Carson帶你學(xué)JVM:圖文解析Java虛擬機(jī)內(nèi)存結(jié)構(gòu)
Carson帶你學(xué)JVM:Java對(duì)象的創(chuàng)建媳搪、內(nèi)存布局 & 訪問定位全過程解析
Carson帶你學(xué)JVM:Java對(duì)象如何判斷存活原則-引用計(jì)數(shù)法 & 引用鏈法
Carson帶你學(xué)JVM:這是一份全面 & 詳細(xì)的垃圾收集算法(GC)講解攻略
Carson帶你學(xué)JVM:常見的垃圾收集器學(xué)習(xí)指南
Carson帶你學(xué)JVM:類加載的全過程解析
Carson帶你學(xué)JVM:你真的了解類加載器嗎?(含雙親委派模型)
Carson帶你學(xué)JVM:方法分派模型-靜態(tài)分派瞧毙、動(dòng)態(tài)分派
目錄
1. 判斷方式
- 垃圾收集器對(duì) Java堆里的對(duì)象 是否進(jìn)行回收的判斷準(zhǔn)則:Java對(duì)象是存活 or 死亡胧华,只有判斷對(duì)象為死亡才會(huì)進(jìn)行回收;
- 在Java虛擬機(jī)中宙彪,判斷對(duì)象是否存活有2種方法:引用計(jì)數(shù)法矩动、引用鏈法(可達(dá)性分析法)
下面會(huì)進(jìn)行詳細(xì)介紹。
2. 引用計(jì)數(shù)法
2.1 方式描述
- 給
Java
對(duì)象添加一個(gè)引用計(jì)數(shù)器 - 每當(dāng)有一個(gè)地方引用它時(shí)释漆,計(jì)數(shù)器 +1悲没;引用失效則 -1;
2.2 判斷對(duì)象存活準(zhǔn)則
當(dāng)計(jì)數(shù)器不為 0 時(shí)男图,判斷該對(duì)象存活示姿;否則判斷為死亡(計(jì)數(shù)器 = 0)甜橱。
2.3 優(yōu)點(diǎn)
- 實(shí)現(xiàn)簡(jiǎn)單
- 判斷高效
2.4 缺點(diǎn)
- 無法解決 對(duì)象間相互循環(huán)引用 的問題
即該算法存在判斷邏輯的漏洞
- 具體描述
<-- 背景 -->
// 對(duì)象objA 和 objB 都有字段 name
// 兩個(gè)對(duì)象相互進(jìn)行引用,除此之外這兩個(gè)人對(duì)象沒有任何引用
objA.name = objB栈戳;
objB.name = objA岂傲;
<-- 問題 -->
// 實(shí)際上這兩個(gè)對(duì)象已經(jīng)不可能再被訪問,應(yīng)該要被垃圾收集器進(jìn)行回收
// 但因?yàn)樗麄兿嗷ヒ米犹矗詫?dǎo)致計(jì)數(shù)器不為0镊掖,這導(dǎo)致引用計(jì)數(shù)算法無法通知垃圾收集器回收該兩個(gè)對(duì)象
正由于該算法存在判斷邏輯漏洞,所以 Java
虛擬機(jī)沒有采用該算法判斷Java
是否存活命锄。
3. 引用鏈法(可達(dá)性分析法)
- 很多主流商用語(yǔ)言(如
Java
堰乔、C#
)都采用 引用鏈法 判斷Java
對(duì)象是否存活。 - 含3個(gè)步驟:
- 可達(dá)性分析
- 第一次標(biāo)記 & 篩選
- 第二次標(biāo)記 & 篩選
3.1 可達(dá)性分析
a. 方式描述
將一系列的 GC Roots
對(duì)象作為起點(diǎn)脐恩,從這些起點(diǎn)開始向下搜索。
- 可作為
GC Root
的對(duì)象有:
1.Java
虛擬機(jī)棧(棧幀的本地變量表)中引用的對(duì)象
2.本地方法棧 中JNI
引用對(duì)象
3.方法區(qū) 中常量侦讨、類靜態(tài)屬性引用的對(duì)象- 向下搜索的路徑 = 引用鏈
如下圖:
b. 判斷 對(duì)象是否可達(dá) 標(biāo)準(zhǔn)
當(dāng)一個(gè)對(duì)象到 GC Roots
沒有任何引用鏈相連時(shí)驶冒,則判斷該對(duì)象不可達(dá)
沒有任何引用鏈相連 =
GC Root
到對(duì)象不可達(dá) = 對(duì)象不可用
特別注意
- 可達(dá)性分析 僅僅只是判斷對(duì)象是否可達(dá),但還不足以判斷對(duì)象是否存活 / 死亡
- 當(dāng)在 可達(dá)性分析 中判斷不可達(dá)的對(duì)象韵卤,只是“被判刑” = 還沒真正死亡
不可達(dá)對(duì)象會(huì)被放在”即將回收“的集合里骗污。
- 要判斷一個(gè)對(duì)象真正死亡,還需要經(jīng)歷兩個(gè)階段:
- 第一次標(biāo)記 & 篩選
- 第二次標(biāo)記 & 篩選
3.2 第一次標(biāo)記 & 篩選
- 對(duì)象 在 可達(dá)性分析中 被判斷為不可達(dá)后沈条,會(huì)被第一次標(biāo)記 & 準(zhǔn)備被篩選
a. 不篩選:繼續(xù)留在 ”即將回收“的集合里需忿,等待回收;
b. 篩選:從 ”即將回收“的集合取出
- 篩選的標(biāo)準(zhǔn):該對(duì)象是否有必要執(zhí)行
finalize()
方法- 若有必要執(zhí)行(人為設(shè)置)蜡歹,則篩選出來屋厘,進(jìn)入下一階段(第二次標(biāo)記 & 篩選);
- 若沒必要執(zhí)行月而,判斷該對(duì)象死亡汗洒,不篩選 并等待回收
當(dāng)對(duì)象無
finalize()
方法 或finalize()
已被虛擬機(jī)調(diào)用過,則視為“沒必要執(zhí)行”
3.3 第二次標(biāo)記 & 篩選
當(dāng)對(duì)象經(jīng)過了第一次的標(biāo)記 & 篩選父款,會(huì)被進(jìn)行第二次標(biāo)記 & 準(zhǔn)備被進(jìn)行 篩選
a. 方式描述
該對(duì)象會(huì)被放到一個(gè) F-Queue
隊(duì)列中溢谤,并由 虛擬機(jī)自動(dòng)建立、優(yōu)先級(jí)低的Finalizer
線程去執(zhí)行 隊(duì)列中該對(duì)象的finalize()
finalize()
只會(huì)被執(zhí)行一次- 但并不承諾等待
finalize()
運(yùn)行結(jié)束憨攒。這是為了防止finalize()
執(zhí)行緩慢 / 停止 使得F-Queue
隊(duì)列其他對(duì)象永久等待世杀。
b. 篩選標(biāo)準(zhǔn)
在執(zhí)行finalize()
過程中,若對(duì)象依然沒與引用鏈上的GC Roots
直接關(guān)聯(lián) 或 間接關(guān)聯(lián)(即關(guān)聯(lián)上與GC Roots
關(guān)聯(lián)的對(duì)象)肝集,那么該對(duì)象將被判斷死亡瞻坝,不篩選(留在”即將回收“集合里) 并 等待回收
3.4 總結(jié)
3步驟 + 以下流程
4. 總結(jié)
- 本文全面講解判斷Java對(duì)象存活的方式
- 接下來我會(huì)對(duì)Java虛擬機(jī)(JVM)進(jìn)行詳細(xì)的分析,歡迎關(guān)注Carson_Ho的簡(jiǎn)書包晰,不定期分享關(guān)于安卓開發(fā)的干貨湿镀,追求短炕吸、平、快勉痴,但卻不缺深度赫模。
請(qǐng)點(diǎn)贊!因?yàn)槟愕墓膭?lì)是我寫作的最大動(dòng)力蒸矛!
Carson帶你學(xué)JVM系列文章瀑罗,具體如下:
Carson帶你學(xué)JVM:這是一份全面 & 詳細(xì)的JVM學(xué)習(xí)指南
Carson帶你學(xué)JVM:圖文解析Java虛擬機(jī)內(nèi)存結(jié)構(gòu)
Carson帶你學(xué)JVM:Java對(duì)象的創(chuàng)建、內(nèi)存布局 & 訪問定位全過程解析
Carson帶你學(xué)JVM:Java對(duì)象如何判斷存活原則-引用計(jì)數(shù)法 & 引用鏈法
Carson帶你學(xué)JVM:這是一份全面 & 詳細(xì)的垃圾收集算法(GC)講解攻略
Carson帶你學(xué)JVM:常見的垃圾收集器學(xué)習(xí)指南
Carson帶你學(xué)JVM:類加載的全過程解析
Carson帶你學(xué)JVM:你真的了解類加載器嗎雏掠?(含雙親委派模型)
Carson帶你學(xué)JVM:方法分派模型-靜態(tài)分派斩祭、動(dòng)態(tài)分派