JVM的垃圾回收算法工作原理-創(chuàng)新互聯(lián)

本篇內(nèi)容主要講解“JVM的垃圾回收算法工作原理”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學(xué)習(xí)“JVM的垃圾回收算法工作原理”吧!

成都創(chuàng)新互聯(lián)公司長期為上千余家客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊從業(yè)經(jīng)驗10年,關(guān)注不同地域、不同群體,并針對不同對象提供差異化的產(chǎn)品和服務(wù);打造開放共贏平臺,與合作伙伴共同營造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為隆安企業(yè)提供專業(yè)的網(wǎng)站設(shè)計制作、網(wǎng)站設(shè)計,隆安網(wǎng)站改版等技術(shù)服務(wù)。擁有10余年豐富建站經(jīng)驗和眾多成功案例,為您定制開發(fā)。

怎么判斷對象是否可以被回收?

共有2種方法,引用計數(shù)法和可達(dá)性分析

1.引用計數(shù)法

所謂引用計數(shù)法就是給每一個對象設(shè)置一個引用計數(shù)器,每當(dāng)有一個地方引用這個對象時,就將計數(shù)器加一,引用失效時,計數(shù)器就減一。當(dāng)一個對象的引用計數(shù)器為零時,說明此對象沒有被引用,也就是“死對象”,將會被垃圾回收.

引用計數(shù)法有一個缺陷就是無法解決循環(huán)引用問題,也就是說當(dāng)對象A引用對象B,對象B又引用者對象A,那么此時A,B對象的引用計數(shù)器都不為零,也就造成無法完成垃圾回收,所以主流的虛擬機都沒有采用這種算法。

public classReferenceFindTest{publicstaticvoidmain(String[] args){MyObject object1 = new MyObject();MyObject object2 = new MyObject();object1.object = object2;object2.object = object1;object1 = null;object2 = null;}}

2.可達(dá)性算法(引用鏈法)

該算法的思想是:從一個被稱為GC Roots的對象開始向下搜索,如果一個對象到GC Roots沒有任何引用鏈相連時,則說明此對象不可用。

在java中可以作為GC Roots的對象有以下幾種:

虛擬機棧中引用的對象  方法區(qū)類靜態(tài)屬性引用的對象  方法區(qū)常量池引用的對象  本地方法棧JNI引用的對象

雖然這些算法可以判定一個對象是否能被回收,但是當(dāng)滿足上述條件時,一個對象比不一定會被回收。當(dāng)一個對象不可達(dá)GC Root時,這個對象并不會立馬被回收,而是出于一個死緩的階段,若要被真正的回收需要經(jīng)歷兩次標(biāo)記。

如果對象在可達(dá)性分析中沒有與GC Root的引用鏈,那么此時就會被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是是否有必要執(zhí)行finalize()方法。當(dāng)對象沒有覆蓋finalize()方法或者已被虛擬機調(diào)用過,那么就認(rèn)為是沒必要的。

如果該對象有必要執(zhí)行finalize()方法,那么這個對象將會放在一個稱為F-Queue的對隊列中,虛擬機會觸發(fā)一個Finalize()線程去執(zhí)行,此線程是低優(yōu)先級的,并且虛擬機不會承諾一直等待它運行完,這是因為如果finalize()執(zhí)行緩慢或者發(fā)生了死鎖,那么就會造成F-Queue隊列一直等待,造成了內(nèi)存回收系統(tǒng)的崩潰。GC對處于F-Queue中的對象進(jìn)行第二次被標(biāo)記,這時,該對象將被移除”即將回收”集合,等待回收。

堆內(nèi)存分代策略以及意義

策略

Java虛擬機將堆內(nèi)存劃分為新生代、老年戰(zhàn)和永久代,永久代是HotSpaot 虛擬機特有的概念,它采用永久代的方式來實現(xiàn)方法區(qū),其他的虛擬機實現(xiàn)沒有這一概念,而且HotSpot也有取消永久代的趨勢,在JDK 1.7中HotSpot已經(jīng)開始了“去永久化”,把原本放在永久代的字符串常量池移出。永久代主要存放常量、類信息、靜態(tài)變量等數(shù)據(jù)(移植到方法區(qū)),與垃圾回收關(guān)系不大,新生代和老年代是垃圾回收的主要區(qū)域。

新生代(Young)

新生成的對象優(yōu)先存放在新生代中,新生代對象朝生夕死,存活率很低,在新生代中,常規(guī)應(yīng)用進(jìn)行一次垃圾收集-般可以回收70% ~ 95%的空間,回收效率很高。

老年代(OldGenerationn)

在新生代中經(jīng)歷了多次(具體看虛擬機配置的閥值)GC后仍然存活下來的對象會進(jìn)入老年代中。老年代中的對象生命周期較長,存活率比較高,在老年代中進(jìn)行GC的頻率相對而言較低,而且回收的速度也比較慢。

永久代(PermanentGenerationn)

永久代存儲類信息、常量、靜態(tài)變量、即時編譯器編譯后的代碼等數(shù)據(jù),對這一區(qū)域而言,Java虛擬機規(guī)范指出可以不進(jìn)行垃圾收集,一般而言不會進(jìn)行垃圾回收。

Jdk1.6及之前: 有永久代, 常量池1.6在方法區(qū)。  Jdk1.7: 有永久代,但已經(jīng)逐步“去永久代”,常量池1.7在堆。  Jdk1.8及之后: 無永久代,常量池1.8在元空間。而元空間是直接存在內(nèi)存中,不在java虛擬機中的,因此元空間依賴于內(nèi)存大小。當(dāng)然你也可以自定義元空間大小。

意義

有了內(nèi)存分代,新創(chuàng)建的對象會在新生代中分配內(nèi)存,經(jīng)過多次回收仍然存活下來的對象存放在老年代中,靜態(tài)屬性、類信息等存放在永久代中,新生代中的對象存活時間短,只需要在新生代區(qū)域中頻繁進(jìn)行GC,老年代中對象生命周期長,內(nèi)存回收的頻率相對較低,不需要頻繁進(jìn)行回收,永久代中回收效果太差, 一般不進(jìn)行垃圾回收,還可以根據(jù)不同年代的特點,采用不同的垃圾收集算法。分代垃圾收集大大提升了垃圾收集效率,這些都是JVM分代的好處。

垃圾回收算法

1.復(fù)制算法

復(fù)制算法將可用內(nèi)存按容量劃分為相等的兩部分,然后每次只使用其中的一塊,當(dāng)一塊內(nèi)存用完時,就將還存活的對象復(fù)制到第二塊內(nèi)存上,然后一次性清楚完第一塊內(nèi)存,再將第二塊上的對象復(fù)制到第一塊。但是這種方式,內(nèi)存的代價太高,每次基本上都要浪費一半的內(nèi)存。

2.標(biāo)記清除算法

是JVM垃圾回收算法中最古老的一個,該算法共分成兩個階段,第一階段從引用根節(jié)點開始標(biāo)記所有被引用的對象,第二階段遍歷整個堆,清除未被標(biāo)記的對象。該算法的缺點是需要暫停整個應(yīng)用,并且在回收以后未使用的空間是不連續(xù),即內(nèi)存碎片,會影響到存儲。

3.標(biāo)記整理算法

此算法結(jié)合了標(biāo)記-清楚算法和復(fù)制算法的優(yōu)點,也分為兩個階段,第一階段從引用根節(jié)點開始標(biāo)記所有被引用的對象,第二階段遍歷整個堆,在回收不存活的對象占用的空間后,會將所有的存活對象往左端空閑空間移動,并更新對應(yīng)的指針。標(biāo)記-整理算法是在標(biāo)記-清除算法的基礎(chǔ)上,又進(jìn)行了對象的移動,因此成本更高,但是卻解決了內(nèi)存碎片的問題,按順序排放,同時解決了復(fù)制算法所需內(nèi)存空間過大的問題。

4.分代收集

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根據(jù)對象存活的生命周期將內(nèi)存劃分為若干個不同的區(qū)域。一般情況下將堆區(qū)劃分為老年代(Tenured Generation)和新生代(Young Generation),在堆區(qū)之外還有一個代就是永久代(Permanet Generation)。老年代的特點是每次垃圾收集時只有少量對象需要被回收,而新生代的特點是每次垃圾回收時都有大量的對象需要被回收,那么就可以根據(jù)不同代的特點采取最適合的收集算法。

a.年輕代回收算法(核心其實就是復(fù)制算法)

HotSpot將新生代劃分為三塊,-塊較大的Eden空間和兩塊較小的Survivor空間,默認(rèn)比例為8: 1: 1。劃分的目的是因為HotSpot采用復(fù)制算法來回收新生代,設(shè)置這個比例是為了充分利用內(nèi)存空間,減少浪費。新生成的對象在Eden區(qū)分配(大對象除外,大對象直接進(jìn)入老年代) ,當(dāng)Eden區(qū)沒有足夠的空間進(jìn)行分配時,虛擬機將發(fā)起一次Minor GC。GC開始時,對象只會存在于Eden區(qū)和From Survivor區(qū),To Survivor區(qū)是空的(作為保留區(qū)域)。

GC進(jìn)行時,Eden區(qū)中所有存活的對象都會被復(fù)制到To Survivor區(qū),而在FromSurvivor區(qū)中,仍存活的對象會根據(jù)它們的年齡值決定去向,年齡值達(dá)到閥值(默認(rèn)為15 ,新生代中的對象每熬過一輪垃圾回收年齡值就加1 ,GC分代年齡存儲在對象的header中)的對象會被移到老年代中,沒有達(dá)到閥值的對象會被復(fù)制到To Survivor區(qū)。

接著清空Eden區(qū)和From Survivor區(qū),新生代中存活的對象都在To Survivor區(qū)。接著, From Survivor區(qū)和To Survivor區(qū)會交換它們的角色,也就是新的To Survivor區(qū)就是上次GC清空的FromSurvivor區(qū),新的From Survivor區(qū)就是.上次GC的To Survivor區(qū),總之,不管怎樣都會保證To Survivor區(qū)在一輪GC后是空的(其實這就是分代收集算法中的年輕代回收算法,稍后我們會看到)。

GC時當(dāng)To Survivor區(qū)沒有足夠的空間存放上一次新生代收集下來的存活對象時,需要依賴?yán)夏甏M(jìn)行分配擔(dān)保,將這些對象存放在老年代中。

b.老年代回收算法(回收主要以標(biāo)記-整理為主)

1)在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對象,就會被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長的對象。

2)內(nèi)存比新生代也大很多(大概比例是1:2),當(dāng)老年代內(nèi)存滿時觸發(fā)Major GC即Full GC,F(xiàn)ull GC發(fā)生頻率比較低,老年代對象存活時間比較長,存活率標(biāo)記高。

c. 持久代(Permanent Generation)的回收算法

用于存放靜態(tài)文件,如Java類、方法等。持久代對垃圾回收沒有顯著影響,但是有些應(yīng)用可能動態(tài)生成或者調(diào)用一些class,例如Hibernate 等,在這種時候需要設(shè)置一個比較大的持久代空間來存放這些運行過程中新增的類。在該區(qū)內(nèi)很少發(fā)生垃圾回收,但是并不代表不發(fā)生GC,在這里進(jìn)行的GC主要是對持久代里的常量池和對類型的卸載。

條件:

1)該類所有的實例都已經(jīng)被回收,即Java堆中不存在該類的任何實例;

2)加載該類的ClassLoader已經(jīng)被回收;

3)該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法。

虛擬機可以對滿足上述3個條件的無用類進(jìn)行回收,此處僅僅是“可以”,而并不是和對象一樣,不使用了就必然回收!

到此,相信大家對“JVM的垃圾回收算法工作原理”有了更深的了解,不妨來實際操作一番吧!這里是創(chuàng)新互聯(lián)建站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

當(dāng)前名稱:JVM的垃圾回收算法工作原理-創(chuàng)新互聯(lián)
網(wǎng)站網(wǎng)址:http://muchs.cn/article38/dcojpp.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、云服務(wù)器、網(wǎng)站內(nèi)鏈、小程序開發(fā)、動態(tài)網(wǎng)站、做網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司