JVM之垃圾收集算法

背景:看完《深入理解Java虛擬機》和相關博客,對JVM還是沒有一個條理清晰的認識,遂提取了書中相關知識點和參考相關優秀博客並整理成JVM專題博文系列,幫助自己鞏固並理清有關JVM的知識重點,也分享出來給有需要的童鞋,如有差錯,歡迎拍磚!

標記-清除算法

最基礎的算法,分標記和清除兩個階段:首先標記處所需要回收的對象,在標記完成後統一回收所有被標記的對象。

它有兩點不足:
一個效率問題,標記和清除過程都效率不高;
一個是空間問題,標記清除之後會產生大量不連續的內存碎片(類似於我們電腦的磁盤碎片),空間碎片太多導致需要分配大對象時無法找到足夠的連續內存而不得不提前觸發另一次垃圾回收動作。


複製算法(標記-複製-清除算法)

爲了解決效率問題,出現了“複製”算法,他將可用內存按容量劃分爲大小相等的兩塊,每次只需要使用其中一塊。當一塊內存用完了,將還存活的對象複製到另一塊上面(移動堆頂指針,按順序分配內存),然後再把剛剛用完的內存空間一次清理掉。這樣就解決了內存碎片問題,但是代價就是可以用內容就縮小爲原來的一半。

目前此種算法主要用於新生代回收(圖中有標註)。
因爲新生代的中98%的對象都是很快就需要被回收的對象,這一點大家在編程時可以體會到,所以並不需要1:1的比例來劃分內存空間,在新生代中JVM是按照“8:1:1”的比例(圖中有標註)來將整個新生代內存劃分爲一塊較大的Eden區和兩塊較小的Survivor區(S0、S1)。

每次使用Eden區和其中一個Survivor區,當發生回收時將Eden區和Survivor區中還存活的對象一次性複製到另一塊Survivor區上,最後清理掉Eden區和剛纔使用過的Survivor區。理想情況下,每次新生代中的可用空間是整個新生代容量的90%(80%+10%),只會有10%的內存會被浪費。實際情況中,如果另外一個10%的Survivor區無法裝下所有還存活的對象時,就會將這些對象直接放入老年代空間中(這塊在後面的分代回收算法會說到,這裏先了解下)。


標記-整理算法(標記-清除-壓縮算法)

複製算法在對象存活率較高時就會進行頻繁的複製操作,效率將降低,而且如果不想浪費50%的內存空間的話,就還需要額外的空間進行分配擔保,以應對存活對象超額的情況。顯然老年代不能採用2)中的複製算法。
因此又有了標記-整理算法,標記過程同標記-清除算法,但是在後續步驟不是直接對對象進行清理,而是讓所有存活的對象都向一側移動,然後直接清理掉端邊界以外的內存。


分代收集算法

當前商業虛擬機的GC都是採用分代收集算法,這種算法並沒有什麼新的思想,而是根據對象存活週期的不同將堆分爲:新生代和老年代,方法區稱爲永久代(在新的版本中已經將永久代廢棄,引入了元空間的概念,永久代使用的是JVM內存而元空間直接使用物理內存),這樣就可以根據各個年代的特點,採用合適的收集算法了。

新生代中的對象“朝生夕死”,每次GC時都會有大量對象死去,少量存活,使用複製算法。新生代又分爲Eden區和Survivor區(Survivor from、Survivor to),大小比例默認爲8:1:1。

老年代中的對象因爲對象存活率高、沒有額外空間進行分配擔保,就使用標記-清除或標記-整理算法。

回收過程

新產生的對象優先進去Eden區,當Eden區滿了之後再使用Survivor from,當Survivor from 也滿了之後就進行Minor GC(新生代GC),將Eden和Survivor from中存活的對象copy進入Survivor to,然後清空Eden和Survivor from,這個時候原來的Survivor from成了新的Survivor to,原來的Survivor to成了新的Survivor from。複製的時候,如果Survivor to 無法容納全部存活的對象,則根據老年代的分配擔保(類似於銀行的貸款擔保)將對象copy進去老年代,如果老年代也無法容納,則進行Full GC(老年代GC)。

大對象直接進入老年代,JVM中有個參數配置-XX:PretenureSizeThreshold,令大於這個設置值的對象直接進入老年代,目的是爲了避免在Eden和Survivor區之間發生大量的內存複製。

長期存活的對象進入老年代,JVM給每個對象定義一個對象年齡計數器,如果對象在Eden出生並經過第一次Minor GC後仍然存活,並且能被Survivor容納,將被移入Survivor並且年齡設定爲1。沒熬過一次Minor GC,年齡就加1,當他的年齡到一定程度(默認爲15歲,可以通過XX:MaxTenuringThreshold來設定),就會移入老年代。但是JVM並不是永遠要求年齡必須達到最大年齡纔會晉升老年代,如果Survivor 空間中相同年齡(如年齡爲x)所有對象大小的總和大於Survivor的一半,年齡大於等於x的所有對象直接進入老年代,無需等到最大年齡要求。

參考

面試必問之JVM原理
一張圖看懂JVM之垃圾回收算法詳解


技術討論 & 疑問建議 & 個人博客

版權聲明: 本博客所有文章除特別聲明外,均採用 CC BY-NC-SA 3.0 許可協議,轉載請註明出處!

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