深入Java底層:GC

概述

下文主要分為以下幾個大模塊進行JVM的GC解讀:

  • 垃圾回收之標記算法
  • 垃圾回收之回收算法
  • 堆內(nèi)存年輕代垃圾收集器
  • 堆內(nèi)存老年代垃圾收集器

1.垃圾回收之標記算法

既然是垃圾回收苹熏,首先就是要判斷哪些對象實例是垃圾,可以被回收题篷,標記算法的用處就在于此

引用計數(shù)法

Java中通過引用關(guān)聯(lián)對象掏膏,顯然可以通過引用計數(shù)的方式來判斷一個對象是否可以被回收。如果一個對象沒有和任何一個引用相關(guān)聯(lián)钠署,那這個對象就可以被回收徘熔。這種算法實現(xiàn)方式簡單糖驴,效率高洪唐,但是無法解決循環(huán)引用的問題钻蹬,如下這段代碼:

public class Main {
    public static void main(String[] args) {
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
         
        object1.object = object2;
        object2.object = object1;
         
        object1 = null;
        object2 = null;
    }
}
 
class MyObject{
    public Object object;
}

由于object1和object2相互引用對方,它們的引用計數(shù)永遠不為0凭需,永遠不會被標記而回收

可達性分析法

Java中采取的就是可達性分析算法问欠。此算法以GC Root為起點進

截屏2019-12-26上午10.47.34.png

行引用鏈搜索,如果GC Root和目標對象之間沒有可達路徑粒蜈,則此對象不可達顺献,但是成為可被回收的對象需要經(jīng)歷兩次可達性分析算法的標記分析,如果兩次都被標記不可達才會被作為”垃圾“枯怖。
常見的GC Root有哪些呢注整?

  • 虛擬機棧中的引用對象
  • 方法區(qū)中的常量引用對象
  • 方法區(qū)中靜態(tài)屬性引用對象
  • 本地方法棧棧中JNI的引用對象
  • 活躍線程的引用對象

2.垃圾回收之回收算法

標記算法完成了”垃圾“的標記,下一步就是回收這些”垃圾“

標記-清除算法(mark-sweep)
標記-清除算法

標記-清除算法分為兩步驟嫁怀,第一步就是利用標記算法找到”垃圾“设捐,第二步清除可被回收的對象借浊。此算法思路簡單易于實現(xiàn)塘淑,但是從上圖中可以看出標記-清除算法比較容易導(dǎo)致內(nèi)存碎片化,如果有較大的對象需要存儲時蚂斤,可能無法找到足夠的內(nèi)存空間存儲存捺,從而又觸發(fā)一次新的垃圾回收動作

復(fù)制算法(copying)

為了解決標記清除算法導(dǎo)致的內(nèi)存碎片化問題,就有了復(fù)制算法曙蒸。
它把內(nèi)存空間分為兩大塊捌治,一塊為對象面,一塊為空閑面纽窟;新創(chuàng)建的對象都在對象面上肖油,直到對象面內(nèi)存空間滿了,把對象面里不是垃圾的存活對象全部復(fù)制到空閑面臂港,然后把整個對象面內(nèi)存空間全部清除森枪,如下圖:

復(fù)制算法

此算法雖然避免了內(nèi)存碎片化视搏,但是可使用的內(nèi)存空間卻減少了一半,并且此算法效率和存貨對象的數(shù)目有很大關(guān)系县袱,適用于存活對象數(shù)目較少的情況

標記-整理算法(mark-compact)

標記整理算法是標記清除算法的更近一步浑娜,在完成垃圾標記后,不是直接清除式散,而是把存活對象都移動至內(nèi)存一端筋遭,按照地址順序排列,最后把末端地址后的內(nèi)存空間全部清除暴拄,如下圖:


標記-整理算法

此算法避免了內(nèi)存碎片化漓滔,也不需要把內(nèi)存空間分為兩大塊,適用于存活對象較多的情況

分代收集算法(generational-collection)

此算法是目前大部分JVM采取的垃圾收集算法乖篷,效率最高次和。它可以理解為一套”組合拳“算法,JVM根據(jù)對象的生命周期將堆劃分為年輕代和老年代那伐,新生代的特點就是每次垃圾回收有較多的垃圾需要回收踏施,老年代的特點就是每次垃圾回收有較少的垃圾需要回收
因此對于年輕代的垃圾回收一般采用復(fù)制算法罕邀,因為年輕代的存活對象較少畅形,反之老年代一般采用標記整理算法,因為老年代的存活對象較多诉探。
年輕代單獨的垃圾回收被稱為Minor GC日熬,年輕代的內(nèi)存劃分其實并不像復(fù)制算里面描述的分為1:1,而是分為一個較大的Eden區(qū)和兩個較小的Survivor區(qū)肾胯,大致空間大小劃分如下:

空間分配

使用新代時竖席,只使用Eden區(qū)和其中一個Survivor區(qū),另一個Survivor區(qū)空閑敬肚。當進行Minor GC時把Eden區(qū)和Survivor區(qū)中的存活對象復(fù)制到另一個空閑的Survivor區(qū)毕荐,然后清除Eden區(qū)和使用過Survivor區(qū)。
整個堆的垃圾收集(包括年輕代和老年代)被稱為Full GC艳馒,也就是當觸發(fā)Full GC時同時也會觸發(fā)Minor GC憎亚,F(xiàn)ull GC的時間大概是Minor GC的十倍。觸發(fā)Full GC有以下幾個條件:

  • 老年代空間不足
  • 調(diào)用System.gc()
  • 還有幾個我也不記得了
關(guān)于垃圾回收的幾個JVM性能調(diào)優(yōu)參數(shù)
  1. -XX:SurvivorRatio:新生代中Eden區(qū)Survivor區(qū)大小的比值弄慰,默認8:1
  2. -XX:NewRatio:老年代和年輕代的大小比值
  3. -XX:MaxTenuringThreshold:對象從年輕代晉升到老年代需要經(jīng)歷的GC次數(shù)的最大閾值

3.年輕代垃圾收集器

Serial收集器

使用-XX:+UseSerialGC設(shè)置年輕代使用此垃圾收集器第美,采用復(fù)制算法。單線程收集陆爽,在進行垃圾收集時必須暫停其他所有工作的線程什往,簡單高效,JVM的Client模式下的默認垃圾收集器


Serial收集器
ParNew收集器

使用-XX:+UseParNewGC設(shè)置年輕代使用此垃圾收集器慌闭,采用復(fù)制算法别威。多線程收集第献,進行垃圾收集時和Serial一樣暫停其他工作線程,其在多核cpu的情況下才能發(fā)揮其優(yōu)勢


ParNew收集器
Parallel Scavenge收集器

使用-XX:+UseParallelGC設(shè)置年輕代使用此垃圾收集器兔港,采用復(fù)制算法庸毫。與ParNew一樣多線程收集,相比于前兩者收集器關(guān)注點為垃圾收集停頓時間衫樊,此垃圾收集器的關(guān)注點為吞吐量(用戶運行代碼的時間/用戶運行代碼的時間+垃圾收集時間),多核cpu才能發(fā)揮優(yōu)勢飒赃,JVM的Server模式下的默認垃圾收集器


Parallel Scavenge收集器

如果對其垃圾收集器的工作原理不太理解,常常使用此垃圾收集器配合-XX:+UseAdaptiveSizePolicy自適應(yīng)調(diào)節(jié)策略科侈,把內(nèi)存調(diào)優(yōu)任務(wù)交給JVM

4.老年代垃圾收集器

Serial Old收集器

使用-XX:+UseSerialOldGC設(shè)置老年代使用此垃圾收集器载佳,采用標記-整理算法。其特點與Serial收集器的特點相同

Parallel Old收集器

使用-XX:+UseParallelGC設(shè)置老年代使用此垃圾收集器臀栈,采用標記-整理算法蔫慧。其特點與Parallel Scavenge相同,多線程收集权薯,吞吐量優(yōu)先姑躲,常與Parallel Scavenge配合使用達到高吞吐量的效果

CMS收集器

使用-XX:+UseConcMarkSweepGC設(shè)置老年代使用此垃圾收集器,采用標記-清除算法盟蚣。CMS是一種以獲取最短停頓時間為目的的收集器黍析,是垃圾收集和工作線程幾乎可以并行工作的收集器(并發(fā)收集器)


CMS收集器
G1收集器

使用-XX:+UseG1GC設(shè)置老年代使用此垃圾收集器,采用復(fù)制+標記-整理算法屎开。它是一款并行并發(fā)收集器阐枣,對整個堆空間進行垃圾收集,能建立可預(yù)測的停頓時間模型

各個收集器之間的可兼容關(guān)系
各個收集器之間的可兼容關(guān)系

圖中上半部分為年輕代垃圾收集器奄抽,下半部分為老年代垃圾收集器蔼两,連線意味著可兼容

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市逞度,隨后出現(xiàn)的幾起案子额划,更是在濱河造成了極大的恐慌,老刑警劉巖第晰,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锁孟,死亡現(xiàn)場離奇詭異彬祖,居然都是意外死亡茁瘦,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門储笑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甜熔,“玉大人,你說我怎么就攤上這事突倍∏幌。” “怎么了盆昙?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長焊虏。 經(jīng)常有香客問我淡喜,道長,這世上最難降的妖魔是什么诵闭? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任炼团,我火速辦了婚禮,結(jié)果婚禮上疏尿,老公的妹妹穿的比我還像新娘瘟芝。我一直安慰自己,他們只是感情好褥琐,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布锌俱。 她就那樣靜靜地躺著,像睡著了一般敌呈。 火紅的嫁衣襯著肌膚如雪贸宏。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天磕洪,我揣著相機與錄音锚赤,去河邊找鬼。 笑死褐鸥,一個胖子當著我的面吹牛线脚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播叫榕,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼浑侥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了晰绎?” 一聲冷哼從身側(cè)響起寓落,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荞下,沒想到半個月后伶选,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡尖昏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年仰税,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片抽诉。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡陨簇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出迹淌,到底是詐尸還是另有隱情河绽,我是刑警寧澤己单,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站耙饰,受9級特大地震影響纹笼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苟跪,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一允乐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧削咆,春花似錦牍疏、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瞻惋,卻和暖如春厦滤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背歼狼。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工掏导, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人羽峰。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓趟咆,卻偏偏與公主長得像,于是被迫代替她去往敵國和親梅屉。 傳聞我的和親對象是個殘疾皇子值纱,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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