Java虛擬機(四)垃圾收集算法
前言
在本系列上一篇文章中我講到了垃圾標記算法,垃圾被標記后,GC就會對垃圾進行收集,垃圾收集有很多種算法,這篇文章就來介紹常用的垃圾收集算法的思想。
1.標記-清除算法
標記-清除算法(Mark-Sweep)是一種常見的基礎垃圾收集算法,它將垃圾收集分為兩個階段:
- 標記階段:標記出可以回收的對象。
- 清除階段:回收被標記的對象所占用的空間。
標記-清除算法之所以是基礎的,是因為后面講到的垃圾收集算法都是在此算法的基礎上進行改進的。標記-清除算法的執行的過程如下圖所示。 
標記-清除算法主要有兩個缺點,一個是標記和清除的效率都不高,另一個從上圖就可以看出來,就是容易產生大量不連續的內存碎片,碎片太多可能會導致后續沒有足夠的連續內存分配給較大的對象,從而提前觸發新的一次垃圾收集動作。
2.復制算法
為了解決標記-清除算法的效率不高的問題,產生了復制算法。它把內存空間劃為兩個相等的區域,每次只使用其中一個區域。垃圾收集時,遍歷當前使用的區域,把存活對象復制到另外一個區域中,最后將當前使用的區域的可回收的對象進行回收。復制算法的執行過程如下圖所示。

這種算法每次都對整個半區進行內存回收,不需要考慮內存碎片的問題,代價就是使用內存為原來的一半。
復制算法的效率跟存活對象的數目多少有很大的關系,如果存活對象很少,復制算法的效率就會很高。由于絕大多數對象的生命周期很短,并且這些生命周期很短的對象都存于新生代中,所以復制算法被廣泛應用于新生代中,關于新生代中復制算法的應用,會在后面的分代收集算法中詳細介紹。
3.標記-壓縮算法
在新生代中可以使用復制算法,但是在老年代就不能選擇復制算法了,因為老年代的對象存活率會較高,這樣會有較多的復制操作,導致效率變低。標記-清除算法可以應用在老年代中,但是它效率不高,在內存回收后容易產生大量內存碎片。因此就出現了一種標記-壓縮算法(Mark-Compact)算法,與標記-清除算法不同的是,在標記可回收的對象后將所有存活的對象壓縮到內存的一端,使他們緊湊的排列在一起,然后對端邊界以外的內存進行回收?;厥蘸?,已用和未用的內存都各自一邊,如下圖所示。

標記-壓縮算法解決了標記-清除算法效率低和容易產生大量內存碎片的問題,它被廣泛的應用于老年代中。
4.分代收集算法
Java堆區的空間劃分
在Java虛擬機中,各種對象的生命周期會有著較大的差別,大部分對象生命周期很短暫,少部分對象生命周期很長,有的甚至和應用程序以及Java虛擬機的運行周期一樣長。因此,應該對不同生命周期的對象采取不同的收集策略,根據生命周期長短將它們分別放到不同的區域,并在不同的區域采用不同的收集算法,這就是分代的概念。
現在主流的Java虛擬機的垃圾收集器都采用分代收集算法(Generational Collection)。Java堆區基于分代的概念,分為新生代(Young Generation)和老年代(Tenured Generation),其中新生代再細分為Eden空間、From Survivor空間和To Survivor空間。因為Eden空間大多對象生命周期很短,所以新生代的空間劃分并不是均分的,HotSpot虛擬機默認Eden空間和兩個Survivor空間的所占的比例為8:1。
分代收集
根據Java堆區的空間劃分,垃圾收集的類型分為兩種,它們分別是:
- Minor Collection:新生代垃圾收集。
- Full Collection:對新生代、老年代和永久代(JDK8 取消永久代,Full Collection掃描不到替代永久代的元空間)進行收集,又可以稱作Majjor Collection。它的收集頻率較低,耗時較長。
當執行一次Minor Collection時,Eden空間的存活對象會被復制到To Survivor空間,并且之前經過一次Minor Collection并在From Survivor空間存活的仍年輕的對象也會復制到To Survivor空間。
有兩種情況Eden空間和From Survivor空間存活的對象不會復制到To Survivor空間,而是晉升到老年代。一種是存活的對象的分代年齡超過-XX:MaxTenuringThreshold(用于控制對象經歷多少次Minor GC才晉升到老年代)所指定的閾值。另一種是To Survivor空間容量達到閾值。
當所有存活的對象被復制到To Survivor空間,或者晉升到老年代,也就意味著Eden空間和From Survivor空間剩下的都是可回收對象,如下圖所示。 
這時GC執行Minor Collection,Eden空間和From Survivor空間都會被清空,而存活的對象都存放在To Survivor空間。
接下來將From Survivor空間和To Survivor空間互換位置,也就是此前的From Survivor空間成為了現在的To Survivor空間,每次Survivor空間互換都要保證To Survivor空間是空的,這就是復制算法在新生代中的應用。在老年代則采用了標記-壓縮算法。
在HotSpot中,基于分代的概念,GC使用的回收算法針對新生代和老年代的特點,采用不同的垃圾收集算法。
浙公網安備 33010602011771號