深入淺出 JVM GC(1)

# 前言

初級(jí) Java 程序員步入中級(jí)程序員的有一個(gè)無(wú)法繞過(guò)的階段------GC(Garbage Collection)。作為 Java 程序員蒋譬,說(shuō)實(shí)話,很幸福号胚,不用像 C 程序員那樣,時(shí)刻關(guān)心著內(nèi)存浸遗,就像網(wǎng)上有句名言------生活從來(lái)都不容易猫胁,只不過(guò)是有人替你負(fù)重前行!是的跛锌,GC 在替我們做這些臟活累活弃秆,GC 像讓我們把精力都放在業(yè)務(wù)上,而不用每時(shí)每刻都在想著內(nèi)存∷杳保現(xiàn)在菠赚,GC 也是每個(gè)語(yǔ)言的標(biāo)準(zhǔn)配置了。不然誰(shuí)會(huì)去使用這個(gè)語(yǔ)言呢氢卡?

然而锈至,作為一個(gè)合格的程序員,對(duì)底層的好奇是進(jìn)步的動(dòng)力译秦,如果一個(gè)程序員失去了好奇心峡捡,那就可以說(shuō)他在程序員這條道路上就結(jié)束了。

難道我們不好奇 GC 到底是怎么做的嗎筑悴?接下來(lái)们拙,我們就分析 GC 做了哪些事情。

實(shí)際上阁吝,GC 主要做3件事情:

  1. 哪些內(nèi)存需要回收砚婆?
  2. 什么時(shí)候回收?
  3. 如何回收突勇?

說(shuō)到底装盯,GC 就是做這3件事情,如果你能解決這3個(gè)問(wèn)題甲馋,那么你也可以實(shí)現(xiàn)一個(gè) GC埂奈。

那我們就一個(gè)一個(gè)問(wèn)題來(lái)看看。

1. 哪些內(nèi)存需要回收

還記得我們之前分享的關(guān)于 JVM 運(yùn)行時(shí)數(shù)據(jù)區(qū)嗎定躏?有堆账磺,有棧,有方法區(qū)(永久代)痊远,還有直接內(nèi)存垮抗,還有 PC 寄存器。其中碧聪,GC 的主要戰(zhàn)場(chǎng)就是堆冒版,當(dāng)然,方法區(qū)也是需要 GC 的矾削。但重點(diǎn)還是堆壤玫。

我們知道豁护,堆中內(nèi)存是共享的哼凯,基本所有的對(duì)象都是在堆中創(chuàng)建欲间。當(dāng)一個(gè)對(duì)象不需要使用了,理論上我們就需要釋放他所占用的內(nèi)存断部。

問(wèn)題來(lái)了猎贴,如何分辨一個(gè)對(duì)象不需要使用了呢?答案是:不可能被任何途徑使用的對(duì)象蝴光。也就是說(shuō)他沒(méi)有了任何引用她渴。我們知道,引用在棧中蔑祟,實(shí)例在堆中趁耗,當(dāng)一個(gè)實(shí)例沒(méi)有了指向他的引用,我們認(rèn)為疆虚,這個(gè)實(shí)例就需要清除并釋放他所占用的內(nèi)存了苛败。

那么 GC 是如何實(shí)現(xiàn)的呢?一般而言有2種方法:

  1. 引用計(jì)數(shù)法(有缺陷径簿,無(wú)法解決循環(huán)引用問(wèn)題罢屈,JVM 沒(méi)有采用)
  2. 可達(dá)性分析(解決了引用計(jì)數(shù)的缺陷,被 JVM 采用)

什么是引用計(jì)數(shù)法呢篇亭?

給對(duì)象中添加一個(gè)引用計(jì)數(shù)器缠捌,每當(dāng)有一個(gè)地方引用他是,計(jì)數(shù)器值就加1译蒂;當(dāng)引用失效時(shí)曼月,計(jì)數(shù)器值就減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能在被使用的柔昼。

雖然乍看這個(gè)算法簡(jiǎn)單哑芹,效率也高,但有一個(gè)問(wèn)題這個(gè)算法無(wú)法解決岳锁,就是循環(huán)引用绩衷。試想一下:A 對(duì)象引用了 B,B 對(duì)象也引用了 A激率,但 A 和 B 都不被別的地方使用咳燕,也就是說(shuō),實(shí)際上這兩個(gè)對(duì)象是垃圾對(duì)象乒躺,但是由于他們互相持有引用招盲,導(dǎo)致他們的引用計(jì)數(shù)器都不為0,因此系統(tǒng)無(wú)法判斷是垃圾嘉冒,也無(wú)法回收他們曹货。

所以咆繁,在現(xiàn)在的 JVM 中,是沒(méi)有使用這個(gè)算法的顶籽。我們知道就行玩般。

引用計(jì)數(shù)法不行,那就再說(shuō)說(shuō)可達(dá)性分析算法礼饱。

這個(gè)算法的基本思想就是通過(guò)一系列的稱為 “GC Roots” 的對(duì)象作為起始點(diǎn)坏为,從這些節(jié)點(diǎn)開(kāi)始向下搜索,所有所走過(guò)的路徑稱為引用鏈(Reference Chain)镊绪,當(dāng)一個(gè)對(duì)象到 GC Roots 沒(méi)有任何引用鏈相連(也就是對(duì)象不可達(dá))時(shí)匀伏,則證明此對(duì)象是不可用的。如下圖所示蝴韭,obj5 , obj6, obj7 雖然互相有關(guān)聯(lián)够颠,但是他們到 GC Roots 是不可達(dá)的,所以他們將會(huì)判定為是可回收的對(duì)象榄鉴。

可達(dá)性分析算法

那么哪些對(duì)象可以作為 GC Roots 對(duì)象呢履磨?

  1. 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
  2. 方法區(qū)中類靜態(tài)屬性引用的對(duì)象牢硅。
  3. 方法區(qū)中常量引用的對(duì)象蹬耘。
  4. 本地方法棧中 JNI (即 native 方法)引用的對(duì)象。

2. 什么時(shí)候回收减余?

注意:即使是在可達(dá)性分析算法中不可達(dá)的對(duì)象综苔,也并非是"非死不可的",這時(shí)候他們實(shí)際上是處于 “緩刑” 階段位岔。因?yàn)橐嬲嬉粋€(gè)對(duì)象的死亡如筛,至少需要經(jīng)歷兩次標(biāo)記過(guò)程:

如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒(méi)有與 GC Roots 相連接的引用鏈,那他將會(huì)被第一次標(biāo)記并且進(jìn)行一次篩選抒抬,篩選的條件是此對(duì)象是否有必要執(zhí)行 finalize 方法杨刨。注意:當(dāng)對(duì)象沒(méi)有覆蓋 finalize 方法,或者 finalize 方法已經(jīng)被虛擬機(jī)調(diào)用過(guò)擦剑,虛擬機(jī)將這兩種情況都視為 “沒(méi)有必要執(zhí)行”妖胀。也就是說(shuō),finalize 方法只會(huì)被執(zhí)行一次惠勒。
=========================================================
如果這個(gè)對(duì)象被判定為有必要執(zhí)行 finalize 方法赚抡,那么這個(gè)對(duì)象將會(huì)放置在一個(gè)叫做 F-Queue 的隊(duì)列之中,并在稍后由一個(gè)虛擬機(jī)自動(dòng)建立的纠屋,低優(yōu)先級(jí)的 Finalizer 線程去執(zhí)行它涂臣。注意:如果一個(gè)對(duì)象在 finalize 方法中運(yùn)行緩慢,將會(huì)導(dǎo)致隊(duì)列后的其他對(duì)象永遠(yuǎn)等待售担,嚴(yán)重時(shí)將會(huì)導(dǎo)致系統(tǒng)崩潰赁遗。
=========================================================
finalize 方法是對(duì)象逃脫死亡命運(yùn)的最后一道關(guān)卡署辉。稍后 GC 將對(duì)隊(duì)列中的對(duì)象進(jìn)行第二次規(guī)模的標(biāo)記,如果對(duì)象要在 finalize 中 “拯救” 自己岩四,只需要將自己關(guān)聯(lián)到引用上即可哭尝,通常是 this。如果這個(gè)對(duì)象關(guān)聯(lián)上了引用炫乓,那么在第二次標(biāo)記的時(shí)候他將被移除出 “即將回收” 的集合刚夺;如果對(duì)象這時(shí)候還沒(méi)有逃脫献丑,那基本上就是真的被回收了末捣。

這里需要注意的一點(diǎn)就是:一個(gè)對(duì)象如果重寫了 finalize 方法,那么這個(gè)方法最多只會(huì)被執(zhí)行一次创橄。

建議:如非必要箩做,不要重寫該方法。可以使用 try-finally 代替妥畏,此方式更好邦邦,更及時(shí)。同時(shí)注意:在 Mysql 的 JDBC 驅(qū)動(dòng)中醉蚁,com.mysql.jdbc.ConnectionImpl 就實(shí)現(xiàn)了 finalize 方法燃辖,作用是:當(dāng)一個(gè) JDBC Connection 被回收時(shí),需要進(jìn)行連接的關(guān)閉网棍,如果開(kāi)發(fā)人員忘記了關(guān)閉黔龟,則在 finalize 方法中進(jìn)行關(guān)閉。但是滥玷,由于其調(diào)用的不確定性氏身,這不能單獨(dú)作為可靠的資源回收手段。

到這里惑畴,我們知道了什么時(shí)候進(jìn)行回收:如果一個(gè)對(duì)象重寫了 finalize 方法且這個(gè)方法沒(méi)有被 JVM 調(diào)用過(guò)蛋欣,那么這個(gè)對(duì)象會(huì)被放入一個(gè)隊(duì)列等待被一個(gè)低優(yōu)先級(jí)的線程執(zhí)行 finalize 方法,如果在這個(gè)方法中對(duì)象不能自救如贷,則這個(gè)對(duì)象在第二次標(biāo)記過(guò)程中就會(huì)被標(biāo)記死亡陷虎,等待 GC 回收。

3. 如何回收杠袱?

如何回收尚猿,這個(gè)問(wèn)題非常的大,涉及到各種垃圾回收算法霞掺,各種垃圾收集器谊路。限于本篇的篇幅,樓主將不會(huì)在這篇文章里深入探討菩彬,這里只會(huì)列出一些大綱缠劝,這些大綱將是后面文章的摘要潮梯,我們將在后面的文章中深入探討如何回收。

那么惨恭,有哪些摘要呢秉馏?

3.1 垃圾回收算法
  1. 標(biāo)記清除算法
  2. 復(fù)制算法
  3. 標(biāo)記整理算法
  4. 分代收集算法(堆如何分代)

這些算法是 GC 的基礎(chǔ),所有 GC 的實(shí)現(xiàn)都是基于這些算法來(lái)清除無(wú)用對(duì)象脱羡,然后釋放內(nèi)存空間萝究。我們將會(huì)在后面的文章一個(gè)一個(gè)講解。

3.2 有哪些垃圾收集器
  1. Serial 串行收集器(只適用于堆內(nèi)存256m 一下的 JVM )
  2. ParNew 并行收集器(Serial 收集器的多線程版本)
  3. Parallel Scavenge (PS 收集器锉罐,該收集器以吞吐量為主要目的帆竹,是1.8的默認(rèn) GC)
  4. CMS 收集器(該收集器全稱 Concurrent Mark Sweep,是一種關(guān)注最短停頓時(shí)間的垃圾收集器)
  5. G1 收集器(JDK 9 的默認(rèn) GC)
3.3 有哪些GC
  1. Young GC(又稱 YGC脓规,minor GC栽连,年輕代 GC)
  2. Old GC (老年代 GC,只有 CMS 才會(huì)單獨(dú)回收 Old 區(qū))
  3. Full GC(又稱 major GC)
  4. Mixed GC(混合 GC侨舆,G1 收集器獨(dú)有)

好秒紧,以上就是如何回收的大綱,我們將在后面的文章中慢慢講解挨下。

總結(jié)

這篇文章主要總結(jié)了什么是 GC 熔恢,以及 GC 的作用,GC 主要做了3件事情臭笆,哪些內(nèi)存需要回收叙淌,什么時(shí)候回收,如何回收耗啦。我們知道了 GC 通過(guò)可達(dá)性分析知道了哪些內(nèi)存需要回收凿菩,那什么時(shí)候回收呢?執(zhí)行 finalize 方法后如果還沒(méi)有復(fù)活帜讲,將被回收衅谷。第三個(gè)問(wèn)題:如何回收呢?這個(gè)問(wèn)題是一個(gè)大課題似将,我們只是列出了一些大綱获黔,比如有哪些垃圾收集器,有哪些垃圾算法在验,有哪些 GC 過(guò)程玷氏。這些細(xì)節(jié)我們將在后面慢慢講解,逐步深入腋舌。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末盏触,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌赞辩,老刑警劉巖雌芽,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異辨嗽,居然都是意外死亡世落,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門糟需,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)屉佳,“玉大人,你說(shuō)我怎么就攤上這事洲押∥浠ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵诅诱,是天一觀的道長(zhǎng)髓堪。 經(jīng)常有香客問(wèn)我,道長(zhǎng)娘荡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任驶沼,我火速辦了婚禮炮沐,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘回怜。我一直安慰自己大年,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布玉雾。 她就那樣靜靜地躺著翔试,像睡著了一般。 火紅的嫁衣襯著肌膚如雪复旬。 梳的紋絲不亂的頭發(fā)上垦缅,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音驹碍,去河邊找鬼壁涎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛志秃,可吹牛的內(nèi)容都是我干的怔球。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼浮还,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼竟坛!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤担汤,失蹤者是張志新(化名)和其女友劉穎又官,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體漫试,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡六敬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驾荣。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片外构。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖播掷,靈堂內(nèi)的尸體忽然破棺而出审编,到底是詐尸還是另有隱情,我是刑警寧澤歧匈,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布垒酬,位于F島的核電站,受9級(jí)特大地震影響件炉,放射性物質(zhì)發(fā)生泄漏勘究。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一斟冕、第九天 我趴在偏房一處隱蔽的房頂上張望口糕。 院中可真熱鬧,春花似錦磕蛇、人聲如沸景描。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)超棺。三九已至,卻和暖如春呵燕,著一層夾襖步出監(jiān)牢的瞬間棠绘,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工虏等, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留弄唧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓霍衫,卻偏偏與公主長(zhǎng)得像候引,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敦跌,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 原文閱讀 前言 這段時(shí)間懈怠了澄干,罪過(guò)逛揩! 最近看到有同事也開(kāi)始用上了微信公眾號(hào)寫博客了,挺好的~給他們點(diǎn)贊麸俘,這博客我...
    碼農(nóng)戲碼閱讀 5,952評(píng)論 2 31
  • 1.什么是垃圾回收辩稽? 垃圾回收(Garbage Collection)是Java虛擬機(jī)(JVM)垃圾回收器提供...
    簡(jiǎn)欲明心閱讀 89,446評(píng)論 17 311
  • 一. 垃圾回收的意義 在C++中,對(duì)象所占的內(nèi)存在程序結(jié)束運(yùn)行之前一直被占用从媚,在明確釋放之前不能分配給其它對(duì)...
    Stan_Z閱讀 1,924評(píng)論 0 25
  • 這篇文章是我之前翻閱了不少的書(shū)籍以及從網(wǎng)絡(luò)上收集的一些資料的整理逞泄,因此不免有一些不準(zhǔn)確的地方,同時(shí)不同JDK版本的...
    高廣超閱讀 15,564評(píng)論 3 83
  • 騎行線路:318國(guó)道 累計(jì)行程:南寧~成都~雙流~新津~邛崍~雅安 今日行程:成都-雙流-新津-邛崍-雅安 騎行距...
    李叁柒閱讀 434評(píng)論 1 4