JVM——垃圾收集

程序計(jì)數(shù)器、虛擬機(jī)棧、本地方法棧3個(gè)區(qū)域隨線程而生,隨線程而滅,因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都具備確定性,因?yàn)榉椒ńY(jié)束或者線程結(jié)束時(shí),內(nèi)存自然就跟隨著回收了。而Java堆和方法區(qū)則不一樣,我們只有在程序處于運(yùn)行期間時(shí)才能知道會(huì)創(chuàng)建哪些對(duì)象,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的,垃圾收集器所關(guān)注的是這部分內(nèi)存。

一、對(duì)象存活判定算法

可達(dá)性分析算法

這個(gè)算法的基本思路就是通過一系列的稱為"GCRoots"的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈(ReferenceChain),當(dāng)一個(gè)對(duì)象到GCRoots沒有任何引用鏈相連(用圖論的話來說,就是從GCRoots到這個(gè)對(duì)象不可達(dá))時(shí),則證明此對(duì)象是不可用的。

如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與GCRoots相連接的引用鏈&對(duì)象覆蓋了finalize()方法&finalize()方法沒有被虛擬機(jī)調(diào)用過(finalize()方法都只會(huì)被系統(tǒng)自動(dòng)調(diào)用一次),那么這個(gè)對(duì)象被判定為有必要執(zhí)行finalize()方法,這個(gè)對(duì)象將會(huì)放置在一個(gè)叫做FQueue的隊(duì)列之中。對(duì)象可以在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個(gè)對(duì)象建立關(guān)聯(lián)即可,譬如把自己(this關(guān)鍵字)賦值給某個(gè)類變量或者對(duì)象的成員變量,那在第二次標(biāo)記時(shí)它將被移除出"即將回收”的集合。finalize()的調(diào)用具有不確定行,只保證方法會(huì)調(diào)用,但不保證方法里的任務(wù)會(huì)被執(zhí)行完,這樣做的原因是,如果一個(gè)對(duì)象在finalize()方法中執(zhí)行緩慢,或者發(fā)生了死循環(huán),將很可能會(huì)導(dǎo)致FQueue隊(duì)列中其他對(duì)象永久處于等待,甚至導(dǎo)致整個(gè)內(nèi)存回收系統(tǒng)崩潰。

強(qiáng)引用:Objcet obj = new Object(),垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。

軟引用:在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收。如果這次回收還沒有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。

弱引用:被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。當(dāng)垃圾收集器工作時(shí),無論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。

虛引用

二、垃圾收集算法

1)標(biāo)記-清除算法(Mark-Sweep)

分為“標(biāo)記”和“清除”兩個(gè)階段:首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象,主要不足有兩個(gè):一個(gè)是效率問題,標(biāo)記和清除兩個(gè)過程的效率都不高;另一個(gè)是空間問題,標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片,空間碎片太多可能會(huì)導(dǎo)致以后在程序運(yùn)行過程中需要分配較大對(duì)象時(shí),無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。


標(biāo)記-清除算法

2)復(fù)制算法(Copying)

它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中的一塊。當(dāng)這一塊的內(nèi)存用完了,就將還存活著的對(duì)象復(fù)制到另外一塊上面,然后再把已使用過的內(nèi)存空間一次清理掉。這樣使得每次都是對(duì)整個(gè)半?yún)^(qū)進(jìn)行內(nèi)存回收,內(nèi)存分配時(shí)也就不用考慮內(nèi)存碎片等復(fù)雜情況,只要移動(dòng)堆頂指針,按順序分配內(nèi)存即可,實(shí)現(xiàn)簡(jiǎn)單,運(yùn)行高效。只是這種算法的代價(jià)是將內(nèi)存縮小為了原來的一半,未免太高了一點(diǎn)。


復(fù)制算法

新生代中的對(duì)象98%是“朝生夕死”的,所以并不需要按照1:1的比例來劃分內(nèi)存空間,而是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中一塊Survivor。當(dāng)回收時(shí),將Eden和Survivor中還存活著的對(duì)象一次性地復(fù)制到另外一塊Survivor空間上,最后清理掉Eden和剛才用過的Survivor空間。HotSpot虛擬機(jī)默認(rèn)Eden和Survivor的大小比例是8:1,也就是每次新生代中可用內(nèi)存空間為整個(gè)新生代容量的90%(80%+10%),只有10%的內(nèi)存會(huì)被“浪費(fèi)”。當(dāng)然,98%的對(duì)象可回收只是一般場(chǎng)景下的數(shù)據(jù),我們沒有辦法保證每次回收都只有不多于10%的對(duì)象存活,當(dāng)Survivor空間不夠用時(shí),需要依賴其他內(nèi)存(這里指老年代)進(jìn)行分配擔(dān)保(Handle Promotion)。

內(nèi)存的分配擔(dān)保也一樣,如果另外一塊Survivor空間沒有足夠空間存放上一次新生代收集下來的存活對(duì)象時(shí),這些對(duì)象將直接通過分配擔(dān)保機(jī)制進(jìn)入老年代。

3)標(biāo)記-整理算法(Mark-Compact)

復(fù)制收集算法在對(duì)象存活率較高時(shí)就要進(jìn)行較多的復(fù)制操作,效率將會(huì)變低。更關(guān)鍵的是,如果不想浪費(fèi)50%的空間,就需要有額外的空間進(jìn)行分配擔(dān)保,以應(yīng)對(duì)被使用的內(nèi)存中所有對(duì)象都100%存活的極端情況,所以在老年代一般不能直接選用這種算法。根據(jù)老年代的特點(diǎn),有人提出了另外一種“標(biāo)記整理”(MarkCompact)算法,標(biāo)記過程仍然與“標(biāo)記清除”算法一樣,但后續(xù)步驟不是直接對(duì)可回收對(duì)象進(jìn)行清理,而是讓所有存活的對(duì)象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。


標(biāo)記整理算法

4)分代收集算法(Generational Collectioin)

根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴?。新生代中,每次垃圾收集時(shí)都發(fā)現(xiàn)有大批對(duì)象死去,只有少量存活,那就選用復(fù)制算法,只需要付出少量存活對(duì)象的復(fù)制成本就可以完成收集。而老年代中因?yàn)閷?duì)象存活率高、沒有額外空間對(duì)它進(jìn)行分配擔(dān)保,就必須使用“標(biāo)記—清理”或者“標(biāo)記—整理”算法來進(jìn)行回收。


參考:

《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • @@@@@@,垃圾收集算法 (復(fù)制算法回收速度快對(duì)應(yīng)Eden回收,標(biāo)記整理速度慢對(duì)應(yīng)老年代回收) 1,標(biāo)記清除算法...
    一個(gè)閑的蛋疼的大專生閱讀 292評(píng)論 0 0
  • 在本篇開始之前有幾個(gè)問題需要大家思考一下: 垃圾收集的哪里? 哪些對(duì)象該被垃圾收集? 對(duì)象如何被回收? 對(duì)象的引用...
    爪哇部落格閱讀 258評(píng)論 0 0
  • 垃圾收集(GC)主要作用在于內(nèi)存的回收,而GC要思考的三件事情: 1,哪些內(nèi)存需要回收? 2,什么時(shí)候回收? 3,...
    文信彡閱讀 277評(píng)論 0 0
  • 垃圾對(duì)象的判斷 引用計(jì)數(shù)法 對(duì)象創(chuàng)建時(shí),給該對(duì)象實(shí)例分配給一個(gè)變量,該變量計(jì)數(shù)設(shè)置為1。當(dāng)該對(duì)象引用被調(diào)用時(shí),計(jì)數(shù)...
    玄冰0825閱讀 192評(píng)論 0 0
  • 轉(zhuǎn)載自 http://flora95.github.io/2015/12/13/Java-Garbage-Coll...
    lsfire閱讀 342評(píng)論 1 2

友情鏈接更多精彩內(nèi)容