本節(jié)內(nèi)容的概要如下;

對(duì)象已死嗎?
?
一、判斷對(duì)象是否存活的算法
1、引用計(jì)數(shù)器算法
給對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器值就加1;當(dāng)引用失效時(shí),計(jì)數(shù)器值就減1;任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。
客觀地說(shuō),引用計(jì)數(shù)算法(Reference Counting)的實(shí)現(xiàn)簡(jiǎn)單,判定效率也很高,在大部分情況下它都是一個(gè)不錯(cuò)的算法,但是,至少主流的Java虛擬機(jī)里面沒(méi)有選用引用計(jì)數(shù)算法來(lái)管理內(nèi)存,其中最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題。
?
2、可達(dá)性分析算法
這個(gè)算法的基本思路就是通過(guò)一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開(kāi)始向下搜索,搜索所走過(guò)的路徑稱為引用鏈(Reference Chain),當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連(用圖論的話來(lái)說(shuō),就是從GC Roots到這個(gè)對(duì)象不可達(dá))時(shí),則證明此對(duì)象是不可用的。
如圖3-1所示,對(duì)象object 5、object 6、object 7雖然互相有關(guān)聯(lián),但是它們到GC Roots是不可達(dá)的,所以它們將會(huì)被判定為是可回收的對(duì)象。
?

圖3-1 可達(dá)性分析算法判定對(duì)象是否可回收
?
在Java語(yǔ)言中,可作為GC Roots的對(duì)象包括下面幾種:
- 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
- 方法區(qū)中類靜態(tài)屬性引用的對(duì)象。
- 方法區(qū)中常量引用的對(duì)象。
- 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象。
?
二、引用類型
在JDK 1.2之后,Java對(duì)引用的概念進(jìn)行了擴(kuò)充,將引用分為強(qiáng)引用(Strong Reference)、軟引用(Soft Reference)、弱引用(Weak Reference)、虛引用(Phantom Reference)4種,這4種引用強(qiáng)度依次逐漸減弱。
1、強(qiáng)引用
強(qiáng)引用就是指在程序代碼之中普遍存在的,類似“Object obj = new Object()”這類的引用,只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
2、軟引用
軟引用是用來(lái)描述一些還有用但并非必需的對(duì)象。對(duì)于軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍之中進(jìn)行第二次回收。如果這次回收還沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常。在JDK 1.2之后,提供了SoftReference類來(lái)實(shí)現(xiàn)軟引用。
3、弱引用
弱引用也是用來(lái)描述非必需對(duì)象的,但是它的強(qiáng)度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前。當(dāng)垃圾收集器工作時(shí),無(wú)論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。在JDK 1.2之后,提供了WeakReference類來(lái)實(shí)現(xiàn)弱引用。
4、虛引用
虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關(guān)系。一個(gè)對(duì)象是否有虛引用的存在,完全不會(huì)對(duì)其生存時(shí)間構(gòu)成影響,也無(wú)法通過(guò)虛引用來(lái)取得一個(gè)對(duì)象實(shí)例。為一個(gè)對(duì)象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是能在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知。在JDK 1.2之后,提供了PhantomReference類來(lái)實(shí)現(xiàn)虛引用。
?
三、 生存還是死亡
即使在可達(dá)性分析算法中不可達(dá)的對(duì)象,也并非是“非死不可”的,這時(shí)候它們暫時(shí)處于“緩刑”階段,要真正宣告一個(gè)對(duì)象死亡,至少要經(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ì)象沒(méi)有覆蓋finalize()方法,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過(guò),虛擬機(jī)將這兩種情況都視為“沒(méi)有必要執(zhí)行”。
如果這個(gè)對(duì)象被判定為有必要執(zhí)行finalize()方法,那么這個(gè)對(duì)象將會(huì)放置在一個(gè)叫做F-Queue的隊(duì)列之中,并在稍后由一個(gè)由虛擬機(jī)自動(dòng)建立的、低優(yōu)先級(jí)的Finalizer線程去執(zhí)行它。這里所謂的“執(zhí)行”是指虛擬機(jī)會(huì)觸發(fā)這個(gè)方法,但并不承諾會(huì)等待它運(yùn)行結(jié)束,這樣做的原因是,如果一個(gè)對(duì)象在finalize()方法中執(zhí)行緩慢,或者發(fā)生了死循環(huán)(更極端的情況),將很可能會(huì)導(dǎo)致F-Queue隊(duì)列中其他對(duì)象永久處于等待,甚至導(dǎo)致整個(gè)內(nèi)存回收系統(tǒng)崩潰。finalize()方法是對(duì)象逃脫死亡命運(yùn)的最后一次機(jī)會(huì),稍后GC將對(duì)F-Queue中的對(duì)象進(jìn)行第二次小規(guī)模的標(biāo)記,如果對(duì)象要在finalize()中成功拯救自己——只要重新與引用鏈上的任何一個(gè)對(duì)象建立關(guān)聯(lián)即可,譬如把自己(this關(guān)鍵字)賦值給某個(gè)類變量或者對(duì)象的成員變量,那在第二次標(biāo)記時(shí)它將被移除出“即將回收”的集合;如果對(duì)象這時(shí)候還沒(méi)有逃脫,那基本上它就真的被回收了。
?
四、回收方法區(qū)
方法區(qū)(或者HotSpot虛擬機(jī)中的永久代),進(jìn)行垃圾收集的“性價(jià)比”一般比較低。
永久代的垃圾收集主要回收兩部分內(nèi)容:廢棄常量和無(wú)用的類。
如何判定廢棄常量:沒(méi)有任何對(duì)象引用
如何判定一個(gè)類是否是“無(wú)用的類”,類需要同時(shí)滿足下面3個(gè)條件才能算是“無(wú)用的類”:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-624667.html
- 該類所有的實(shí)例都已經(jīng)被回收,也就是Java堆中不存在該類的任何實(shí)例。
- 加載該類的ClassLoader已經(jīng)被回收。
- 該類對(duì)應(yīng)的java.lang.Class 對(duì)象沒(méi)有在任何地方被引用,無(wú)法在任何地方通過(guò)反射訪問(wèn)該類的方法。
在大量使用反射、動(dòng)態(tài)代理、CGLib等ByteCode框架、動(dòng)態(tài)生成JSP以及OSGi這類頻繁自定義ClassLoader的場(chǎng)景都需要虛擬機(jī)具備類卸載的功能,以保證永久代不會(huì)溢出。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-624667.html
到了這里,關(guān)于《深入理解Java虛擬機(jī)》讀書筆記:判斷對(duì)象是否存活的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!