更新時(shí)間:2021-10-22 來(lái)源:黑馬程序員 瀏覽量:
添加QQ(注意~~添加好友界面,選擇找人):435946716,【免費(fèi)】獲取《JVM核心教程:JVM從門到精通_JVM虛擬機(jī)底層原理深入教程》全套視頻教程+配套資料。
在堆里面存放著各種各類的Java對(duì)象,垃圾收集器在對(duì)堆進(jìn)行垃圾回收時(shí),首要就是判斷哪些對(duì)象還活著,哪些對(duì)象已經(jīng)死去(即不被任何途徑引用的對(duì)象)。
引用計(jì)數(shù)器算法:
引用計(jì)數(shù)器算法簡(jiǎn)單概括為:給對(duì)象添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用該對(duì)象時(shí),計(jì)數(shù)器+1,當(dāng)引用失效時(shí),計(jì)數(shù)器-1,任何時(shí)刻,當(dāng)計(jì)數(shù)器為0的時(shí)候,該對(duì)象不再被引用。客觀的說(shuō),引用計(jì)數(shù)器的實(shí)現(xiàn)簡(jiǎn)單,判定效率也高,大部分場(chǎng)景下是一個(gè)不錯(cuò)的選擇。但是,當(dāng)前主流的Jvm均沒(méi)有采用標(biāo)記清除算法,原因在于,它很難解決對(duì)象之間互相循環(huán)調(diào)用的情況。
可達(dá)性分析算法:
在主流的商用程序語(yǔ)言(如C#, Java)的主流實(shí)現(xiàn)中,都是通過(guò)可達(dá)性分析來(lái)判斷對(duì)象是否存活,這個(gè)算法的思想就是通過(guò)一系列的成為"GC
Roots"的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑成為引用鏈,當(dāng)一個(gè)對(duì)象到"GC
Roots"沒(méi)有任何引用鏈相連,則證明此對(duì)象是不可用的。
如圖所示,雖然Obj5, Obj6, Obj7互有關(guān)聯(lián),但是他們到GC root沒(méi)有任何引用鏈,所以判定為需要被回收的對(duì)象。
常說(shuō)的GC(Garbage Collector) roots,特指的是垃圾收集器(Garbage Collector)的對(duì)象,GC會(huì)收集那些不是GC roots且沒(méi)有被GC roots引用的對(duì)象。
在Java中,可以作為GC Roots的對(duì)象包括下面幾種:
·虛擬機(jī)棧中引用的對(duì)象;
·方法區(qū)中類靜態(tài)屬性引用的對(duì)象;
·方法區(qū)中的常量引用的對(duì)象;
·本地方法棧中JNI(即一般說(shuō)的Native方法)的引用的對(duì)象;
再談引用
無(wú)論是通過(guò)引用計(jì)數(shù)器判斷的引用數(shù)量,還是通過(guò)可達(dá)性分析判斷出的引用鏈?zhǔn)欠窨蛇_(dá),判定對(duì)象是否存活都跟引用有關(guān)。在JDK1.2以前,引用被定義為當(dāng)一個(gè)reference類型的數(shù)據(jù)代表的是另外一塊內(nèi)存的起始地址,該類型的數(shù)據(jù)被稱之為引用,這種定義很純粹,但是也很狹隘,一個(gè)對(duì)象在這種定義下只有被引用和沒(méi)有被引用兩種狀態(tài)。對(duì)于描述一些“食之無(wú)味,棄之可惜”的對(duì)象就顯得無(wú)能為力。我們希望能描述這類對(duì)象,當(dāng)內(nèi)存足夠的時(shí)候,將它存放在內(nèi)存中,當(dāng)內(nèi)存空間進(jìn)行垃圾回收后顯得還是內(nèi)存緊張時(shí),可以回收這部分對(duì)象,很多系統(tǒng)的緩存功能都符合這樣的應(yīng)用場(chǎng)景。因此在JDK1.2以后對(duì)引用進(jìn)行重新的擴(kuò)充,分為強(qiáng)引用,軟引用,弱引用,虛引用4中,這四種引用的強(qiáng)度依次遞減。
強(qiáng)引用:
強(qiáng)引用是在代碼中普遍存在的,類似于Object obj = new Object(),只要強(qiáng)引用一直存在,垃圾收集器就永遠(yuǎn)不會(huì)回收被引用的對(duì)象。
軟引用:
軟引用用來(lái)描述一些還有用但并非必須的對(duì)象,對(duì)于軟引用關(guān)聯(lián)著的對(duì)象,當(dāng)內(nèi)存溢出異常發(fā)生之前,通過(guò)垃圾回收進(jìn)行二次回收。如果二次回收完成之后,系統(tǒng)內(nèi)存依然不夠,才會(huì)拋出內(nèi)存溢出異常,在jdk1,2以后用SoftReference類來(lái)實(shí)現(xiàn)軟引用。
弱引用:
弱引用也是用來(lái)描述非必須對(duì)象的,但是它的強(qiáng)度相比于軟引用來(lái)說(shuō)更弱一些,它僅僅能生存到下一次垃圾回收之前。當(dāng)垃圾收集時(shí),無(wú)論內(nèi)存是否足夠,弱引用的對(duì)象都要被回收,在jdk1.2以后用WeakReference類來(lái)實(shí)現(xiàn)弱引用
虛引用:
虛引用是最弱的一種引用關(guān)系,一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)一個(gè)虛引用來(lái)獲取一個(gè)實(shí)例對(duì)象。為一個(gè)對(duì)象設(shè)置弱引用的唯一目的就是該對(duì)象在垃圾回收時(shí)受到一個(gè)系統(tǒng)通知,Jdk1,2以后用PhantomReference實(shí)現(xiàn)虛引用。
生存還是死亡?
即使在可達(dá)性分析中,沒(méi)有引用鏈到達(dá)GC Roots,也并非是“非死不可”的。這個(gè)時(shí)候?qū)ο筇幱诰徯屉A段,要正式宣告死亡,至少要經(jīng)歷兩次標(biāo)記的過(guò)程。如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒(méi)有與GC Roots相連接的引用鏈,那它將會(huì)被第一次標(biāo)記并進(jìn)行一次篩選,篩選的條件是此對(duì)象是否要執(zhí)行finalize()方法,當(dāng)對(duì)象么有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過(guò),虛擬機(jī)將這兩種情況都視為不必要執(zhí)行finalize()方法。
如果該對(duì)象被判定要執(zhí)行finalize()方法,那么這個(gè)對(duì)象會(huì)被放在一個(gè)叫F-Queue的隊(duì)列中,并在稍后有一個(gè)虛擬機(jī)自行創(chuàng)建的,優(yōu)先級(jí)較低的線程去執(zhí)行它,這里的執(zhí)行是指會(huì)觸發(fā)finalize()方法,但并不會(huì)等待它執(zhí)行結(jié)束。這樣做的原因是如果一個(gè)對(duì)象在執(zhí)行finalize()時(shí)非常緩慢,或者執(zhí)行了死循環(huán),這樣就會(huì)導(dǎo)致F-Queue中的其他對(duì)象處于等待中,嚴(yán)重的會(huì)導(dǎo)致整個(gè)垃圾回收系統(tǒng)崩潰。finalize()是對(duì)象逃脫死亡的最后一次機(jī)會(huì),稍后GC將對(duì)F-Queue中的對(duì)象進(jìn)行二次標(biāo)記,如果對(duì)象要在finalize()中拯救自己的話,只能重新與引用鏈上的任意一個(gè)對(duì)象建立關(guān)聯(lián)即可,比如把對(duì)象自己(this關(guān)鍵字)賦值給其他成員變量或者對(duì)象,那在第二次標(biāo)記時(shí)就被移出即將回收的集合,如果沒(méi)有關(guān)聯(lián)上,基本可以確定要被回收了。
猜你喜歡
垃圾收集算法有哪些?圖文詳細(xì)介紹
2021-10-22Java開(kāi)發(fā)項(xiàng)目《萬(wàn)信金融》企業(yè)級(jí)開(kāi)發(fā)實(shí)戰(zhàn)(springboot+springcloud)
2021-10-21什么是匿名內(nèi)部類?怎樣編寫匿名內(nèi)部類?
2021-10-18使用?this關(guān)鍵字調(diào)用本類的構(gòu)造方法
2021-10-15什么是代碼塊?什么是普通代碼塊?
2021-10-15微服務(wù)技術(shù)棧教程:實(shí)用篇+高級(jí)篇+面試篇【全184集】
2021-10-13