JVM 常見的垃圾回收算法
1. 前言
本節(jié)主要講解垃圾回收算法,并對每一種算法進(jìn)行講解。垃圾回收算法在垃圾回收器中占據(jù)著十分重要的地位,對本節(jié)內(nèi)容一定要格外重視。本節(jié)主要內(nèi)容如下:
- 標(biāo)記-清除(Mark-Sweep)算法的原理及缺陷,為本節(jié)重點(diǎn)內(nèi)容之一;
- 復(fù)制(coping)算法的原理及缺陷,為本節(jié)重點(diǎn)內(nèi)容之一;
- 標(biāo)記-整理(Mark-Compact)算法的原理及缺陷,為本節(jié)重點(diǎn)內(nèi)容之一;
- 分代收集理論的原理及思想,為本節(jié)重點(diǎn)內(nèi)容之一;
通篇皆為重點(diǎn)內(nèi)容,務(wù)必要用心學(xué)習(xí)。
2. 垃圾回收算法種類
我們先來討論一個(gè)問題,垃圾回收算法有幾種?
如果單純從一些博客或者論壇上的內(nèi)容來說,部分作者會(huì)將垃圾回收分為如下 4 種算法:
- 標(biāo)記-清除(Mark-Sweep)算法;
- 復(fù)制(coping)算法;
- 標(biāo)記-整理(Mark-Compact)算法;
- 分代收集算法。
但是這種分類是不準(zhǔn)確的,準(zhǔn)確來說,垃圾回收只有 3 種算法:
- 標(biāo)記-清除(Mark-Sweep)算法;
- 復(fù)制(coping)算法;
- 標(biāo)記-整理(Mark-Compact)算法。
為什么會(huì)有所謂的“分代收集算法”呢? 此處我們埋下一個(gè)伏筆,后文中我會(huì)在適當(dāng)?shù)牡胤浇o予解釋。
3. 標(biāo)記-清除(Mark-Sweep)算法
標(biāo)記 - 清除(Mark-Sweep)算法是最基本的算法。
基本概念:標(biāo)記-清除算法就如同它的名字一樣,分為“標(biāo)記”和“清除”兩個(gè)階段:
- 首先標(biāo)記出所有需要回收的對象,這就是標(biāo)記階段;
- 標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對象,這就是所謂的清除階段。
缺點(diǎn):這種算法的不足主要體現(xiàn)在效率和空間。
- 從效率的角度講:標(biāo)記和清除兩個(gè)過程的的效率都不高;
- 從空間的角度講:標(biāo)記清楚后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,內(nèi)存碎片太多可能會(huì)導(dǎo)致以后程序運(yùn)行過程中在需要分配較大對象時(shí),無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)一次垃圾回收動(dòng)作。
為了更加透徹的理解標(biāo)記-清除(Mark-Sweep)算法,我們來看下如下示意圖,通過直觀的圖形展示,徹底搞懂標(biāo)記-清除(Mark-Sweep)算法。
4. 復(fù)制(coping)算法
Tips:前文提到過,標(biāo)記-清除(Mark-Sweep)算法從效率的角度講,"標(biāo)記"和"清除"兩個(gè)過程的的效率都不高,為了提升效率,我們引出了復(fù)制(coping)算法。
基本概念:復(fù)制算法是為了解決效率問題而出現(xiàn)的,它將可用的內(nèi)存分為兩塊,每次只用其中的一塊,當(dāng)這一塊內(nèi)存用完了,就將還存活著的對象復(fù)制到另外一塊上面,然后再把已經(jīng)使用過的內(nèi)存一次性清理掉。這樣每次只需要對整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配的執(zhí)行過程如下圖所示:
缺點(diǎn):不過這種算法有個(gè)缺點(diǎn),內(nèi)存縮小為原來的一半,這樣代價(jià)太高了。
現(xiàn)在的商用模擬機(jī)都采用這種算法來回收新生代,不過研究表明1:1的比例非常不科學(xué),因此新生代的內(nèi)存被劃分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。
每次回收時(shí),將Eden和Survivor中還存活著的對象一次性復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才使用過的Survivor空間。
HotSpot虛擬機(jī)默認(rèn)Eden區(qū)和Survivor區(qū)的比例為8:1,意思是每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%。當(dāng)然,我們沒有辦法保證每次回收都只有不多于10%的對象存活,當(dāng)Survivor空間不夠用時(shí),需要依賴?yán)夏甏M(jìn)行分配擔(dān)保(Handle Promotion)。
5. 標(biāo)記-整理(Mark-Compact)算法
Tips:復(fù)制算法在對象存活率較高的場景下要進(jìn)行大量的復(fù)制操作,效率還是很低。并且每次只使用一半的內(nèi)存空間,資源浪費(fèi)嚴(yán)重。標(biāo)記-整理(Mark-Compact)算法解決了內(nèi)存利用率的問題,并且減少了大量復(fù)制的問題。
根據(jù)老年代的特點(diǎn),有人提出了另外標(biāo)記-整理(Mark-Compact)算法,標(biāo)記過程與標(biāo)記-整理(Mark-Compact)算法一樣,不過不是直接對可回收對象進(jìn)行整理,而是讓所有存活對象都向一端移動(dòng),然后清理掉邊界以外的內(nèi)存。標(biāo)記-整理算法的工作過程如圖:
6. 分代清理
問題:我們上文埋下了伏筆,分代清理到底是不是第四種算法呢?
解答:不是,我們通常稱之為分代收集理論,或稱之為分代收集思想。目前虛擬機(jī)基本都采用分代收集理論來進(jìn)行垃圾回收。
分代收集理論結(jié)合了以上的 3 種算法,根據(jù)對象的生命周期的不同將內(nèi)存劃分為幾塊,然后根據(jù)各塊的特點(diǎn)采用最適當(dāng)?shù)氖占惴?。?zhǔn)確的說,分代收集理論就是在不同的內(nèi)存區(qū)域使用不同的算法,它是 以上 3 種算法的使用者。
因此說,分代清理并非是一種單獨(dú)的算法,而是一種收集理論。
7. 小結(jié)
本節(jié)內(nèi)容主要講解了垃圾回收的 3 種算法和分代收集理論。通篇皆為重點(diǎn)掌握內(nèi)容,是垃圾回收的核心知識點(diǎn)。學(xué)習(xí)者可以結(jié)合給出的示意圖進(jìn)行理解,這樣能夠更好地掌握本節(jié)所講的內(nèi)容。