聊一下JVM是如何進行垃圾回收的演算法

大雄45發表於2021-07-23
導讀 我們聊一下JVM是如何進行回收的。
標記-清除

顧名思義,其過程分為兩個階段,分別是 標記清除。首先標記出所有需要回收的物件,然後統一對標記的物件進行回收。這個演算法的十分的侷限,首先標記和清除的兩個過程效率都不高,而且這樣的清理方式會產生大量的記憶體碎片,什麼意思呢?

就是雖然總體看起來還有足夠的剩餘記憶體空間,但是他們都是以一塊很小的記憶體分散在各個地方。如果此時需要為一個大物件申請空間,即使總體上的記憶體空間足夠,但是JVM無法找到一塊這麼大的連續記憶體空間,就會導致觸發一次GC。

聊一下JVM是如何進行垃圾回收的演算法聊一下JVM是如何進行垃圾回收的演算法

複製

其大致的思路是,將現有的記憶體空間分為兩半A和B,所有的新物件的記憶體都在A中分配,然後當A用完了之後,就開始物件存活判斷,將A中還存活的物件複製到B去,然後一次性將A中的記憶體空間回收掉。

聊一下JVM是如何進行垃圾回收的演算法聊一下JVM是如何進行垃圾回收的演算法

這樣一來就不會出現使用 標記-清除所造成的記憶體碎片的問題了。但是,它仍然有自己的不足。那就是以記憶體空間縮小了一半為代價,而在某些情況下,這種代價其實是很高的。
堆中新生代就是採用的複製演算法。剛剛提到過,新生代被分為了Eden、From Survivor、To Survivor,由於幾乎所有的新物件都會在這裡分配記憶體,所以Eden區比Survivor區要大很多。因此Eden區和Survivor區就不需要按照複製演算法預設的1:1的來分配記憶體。
在HotSpot中Eden和Survivor的比例預設是8:1,也就意味著只有10%的空間會被浪費掉。

看到這你可能會發現一個問題。
既然你的Eden區要比Survivor區大這麼多,要是一次GC之後的存活物件的大小 大於Survivor區的總大小該怎麼處理?
的確,在新生代GC時,最壞的情況就是Eden區的所有物件都是存活的,那這個JVM會怎麼處理呢?這裡需要引入一個概念叫做 記憶體分配擔保
當發生了上面這種情況,新生代需要老年代的記憶體空間來做擔保,把Survivor存放不下的物件直接存進老年代中。

標記-整理

標記-整理其GC的過程與標記-清楚是一樣的,只不過會讓所有的存活物件往同一邊移動,這樣一來就不會像標記-整理那樣留下大量的記憶體碎片。

聊一下JVM是如何進行垃圾回收的演算法聊一下JVM是如何進行垃圾回收的演算法

 

分代收集

這也是當前主流虛擬機器所採用的演算法,其實就是針對不同的記憶體區域的特性,使用上面提到過的不同的演算法。

例如新生代的特性是大部分的物件都是需要被回收掉的,只有少量物件會存活下來。所以新生代一般都是採用 複製演算法

而老年代屬於物件存活率都很高的記憶體空間,則採用 標記-清除標記-整理演算法來進行垃圾回收。

原文來自:

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2783049/,如需轉載,請註明出處,否則將追究法律責任。

相關文章