Java基础:JVM垃圾回收算法
眾所周知,Java的垃圾回收是不需要程序員去手動(dòng)操控的,而是由JVM去完成。本文介紹JVM進(jìn)行垃圾回收的各種算法。
- 1. 如何確定某個(gè)對象是垃圾
- 1.1. 引用計(jì)數(shù)法
- 1.2. 可達(dá)性分析
- 2. 典型的垃圾回收算法
- 2.1. 標(biāo)記-清除算法(Mark-Sweep)
- 2.2. 復(fù)制算法(Copying)
- 2.3. 標(biāo)記-整理算法(Mark-Compact)
- 2.4. 分代收集算法(Generational Collection)
- 3. 典型的垃圾收集器
- 3.1. Serial/Serial Old
- 3.2. ParNew
- 3.3. Parallel Scavenge
- 3.4. Parallel Old
- 3.5. CMS
- 3.6. G1
- 4. 參考文章
1. 如何確定某個(gè)對象是垃圾
1.1. 引用計(jì)數(shù)法
在Java中,引用和對象是有關(guān)聯(lián)的。如果要操作對象則必須用引用進(jìn)行。因此,很顯然一個(gè)簡單的辦法是通過引用計(jì)數(shù)來判斷一個(gè)對象是否可以回收。簡單說,即一個(gè)對象如果沒有任何與之關(guān)聯(lián)的引用,則說明對象不太可能再被用到,那么這個(gè)對象就是可回收對象。這種方式即是引用計(jì)數(shù)法。這種方式的問題是無法解決循環(huán)引用的問題,舉個(gè)例子:
public static void main(String[] args){Object object1=new Object();Object object2=new Object();object1.object=object2;object2.object=object1;object1=null;object2=null; }顯然,在最后,object1和object2的內(nèi)存塊都不能再被訪問到了,但他們的引用計(jì)數(shù)都不為0,這就會(huì)使他們永遠(yuǎn)不會(huì)被清除。
1.2. 可達(dá)性分析
為了解決引用計(jì)數(shù)法的循環(huán)引用問題,Java使用了可達(dá)性分析的方法。通過一系列的“GC roots”對象作為起點(diǎn)搜索。如果在“GC roots”和一個(gè)對象之間沒有可達(dá)路徑,則稱該對象是不可達(dá)的。要注意的是,不可達(dá)對象不等價(jià)于可回收對象,不可達(dá)對象變?yōu)榭苫厥諏ο笾辽僖?jīng)過兩次標(biāo)記過程。兩次標(biāo)記后仍然是可回收對象,則將面臨回收。
比較常見的將對象視為可回收對象的原因:
- 顯式地將對象的唯一強(qiáng)引用指向新的對象。
- 顯式地將對象的唯一強(qiáng)引用賦值為Null。
- 局部引用所指向的對象(如,方法內(nèi)對象)。
下述代碼中,每次循環(huán)結(jié)束,object都會(huì)被視為可回收對象。
void fun() {.....for(int i=0;i<10;i++) {Object obj = new Object();System.out.println(obj.getClass());} }- 只有弱引用與其關(guān)聯(lián)的對象
2. 典型的垃圾回收算法
在JVM規(guī)范中并沒有明確GC的運(yùn)作方式,各個(gè)廠商可以采用不同的方式去實(shí)現(xiàn)垃圾回收器。這里討論幾種常見的GC算法。
2.1. 標(biāo)記-清除算法(Mark-Sweep)
最基礎(chǔ)的垃圾回收算法,分為兩個(gè)階段,標(biāo)注和清除。標(biāo)記階段標(biāo)記出所有需要回收的對象,清除階段回收被標(biāo)記的對象所占用的空間。如圖:
從圖中我們就可以發(fā)現(xiàn),該算法最大的問題是內(nèi)存碎片化嚴(yán)重,后續(xù)可能發(fā)生大對象不能找到可利用空間的問題。
2.2. 復(fù)制算法(Copying)
為了解決Mark-Sweep算法內(nèi)存碎片化的缺陷而被提出的算法。按內(nèi)存容量將內(nèi)存劃分為等大小的兩塊。每次只使用其中一塊,當(dāng)這一塊內(nèi)存滿后將尚存活的對象復(fù)制到另一塊上去,把已使用的內(nèi)存清掉,如圖:
這種算法雖然實(shí)現(xiàn)簡單,內(nèi)存效率高,不易產(chǎn)生碎片,但是最大的問題是可用內(nèi)存被壓縮到了原本的一半。且存活對象增多的話,Copying算法的效率會(huì)大大降低。
2.3. 標(biāo)記-整理算法(Mark-Compact)
結(jié)合了以上兩個(gè)算法,為了避免缺陷而提出。標(biāo)記階段和Mark-Sweep算法相同,標(biāo)記后不是清理對象,而是將存活對象移向內(nèi)存的一端。然后清除端邊界外的對象。如圖:
2.4. 分代收集算法(Generational Collection)
分代收集法是目前大部分JVM所采用的方法,其核心思想是根據(jù)對象存活的不同生命周期將內(nèi)存劃分為不同的域,一般情況下將GC堆劃分為老生代(Tenured/Old Generation)和新生代(Young Generation)。老生代的特點(diǎn)是每次垃圾回收時(shí)只有少量對象需要被回收,新生代的特點(diǎn)是每次垃圾回收時(shí)都有大量垃圾需要被回收,因此可以根據(jù)不同區(qū)域選擇不同的算法。
目前大部分JVM的GC對于新生代都采取Copying算法,因?yàn)樾律忻看卫厥斩家厥沾蟛糠謱ο?#xff0c;即要復(fù)制的操作比較少,但通常并不是按照1:1來劃分新生代。一般將新生代劃分為一塊較大的Eden空間和兩個(gè)較小的Survivor空間(From Space, To Space),每次使用Eden空間和其中的一塊Survivor空間,當(dāng)進(jìn)行回收時(shí),將該兩塊空間中還存活的對象復(fù)制到另一塊Survivor空間中。
而老生代因?yàn)槊看沃换厥丈倭繉ο?#xff0c;因而采用Mark-Compact算法。
另外,不要忘記在Java基礎(chǔ):Java虛擬機(jī)(JVM)中提到過的處于方法區(qū)的永生代(Permanet Generation)。它用來存儲(chǔ)class類,常量,方法描述等。對永生代的回收主要包括廢棄常量和無用的類。
對象的內(nèi)存分配主要在新生代的Eden Space和Survivor Space的From Space(Survivor目前存放對象的那一塊),少數(shù)情況會(huì)直接分配到老生代。當(dāng)新生代的Eden Space和From Space空間不足時(shí)就會(huì)發(fā)生一次GC,進(jìn)行GC后,Eden Space和From Space區(qū)的存活對象會(huì)被挪到To Space,然后將Eden Space和From Space進(jìn)行清理。如果To Space無法足夠存儲(chǔ)某個(gè)對象,則將這個(gè)對象存儲(chǔ)到老生代。在進(jìn)行GC后,使用的便是Eden Space和To Space了,如此反復(fù)循環(huán)。當(dāng)對象在Survivor區(qū)躲過一次GC后,其年齡就會(huì)+1。默認(rèn)情況下年齡到達(dá)15的對象會(huì)被移到老生代中。
3. 典型的垃圾收集器
垃圾收集算法是垃圾收集器的理論基礎(chǔ),而垃圾收集器就是其具體實(shí)現(xiàn)。下面介紹HotSpot虛擬機(jī)提供的幾種垃圾收集器。
3.1. Serial/Serial Old
最古老的收集器,是一個(gè)單線程收集器,用它進(jìn)行垃圾回收時(shí),必須暫停所有用戶線程。Serial是針對新生代的收集器,采用Copying算法;而Serial Old是針對老生代的收集器,采用Mark-Compact算法。優(yōu)點(diǎn)是簡單高效,缺點(diǎn)是需要暫停用戶線程。
3.2. ParNew
Seral/Serial Old的多線程版本,使用多個(gè)線程進(jìn)行垃圾收集。
3.3. Parallel Scavenge
新生代的并行收集器,回收期間不需要暫停其他線程,采用Copying算法。該收集器與前兩個(gè)收集器不同,主要為了達(dá)到一個(gè)可控的吞吐量。
3.4. Parallel Old
Parallel Scavenge的老生代版本,采用Mark-Compact算法和多線程。
3.5. CMS
Current Mark Sweep收集器是一種以最小回收時(shí)間停頓為目標(biāo)的并發(fā)回收器,因而采用Mark-Sweep算法。
3.6. G1
G1(Garbage First)收集器技術(shù)的前沿成果,是面向服務(wù)端的收集器,能充分利用CPU和多核環(huán)境。是一款并行與并發(fā)收集器,它能夠建立可預(yù)測的停頓時(shí)間模型。
4. 參考文章
Java垃圾回收機(jī)制
from:?https://www.cnblogs.com/cielosun/p/6674431.html
總結(jié)
以上是生活随笔為你收集整理的Java基础:JVM垃圾回收算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入理解JVM(6)——类加载器
- 下一篇: Java集合类ArrayList循环中删