真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Java底層:GC相關(guān)

垃圾回收之垃圾標(biāo)記算法

對(duì)象被判定為垃圾的標(biāo)準(zhǔn):

十多年的密山網(wǎng)站建設(shè)經(jīng)驗(yàn),針對(duì)設(shè)計(jì)、前端、開(kāi)發(fā)、售后、文案、推廣等六對(duì)一服務(wù),響應(yīng)快,48小時(shí)及時(shí)工作處理。成都全網(wǎng)營(yíng)銷的優(yōu)勢(shì)是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動(dòng)調(diào)整密山建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無(wú)論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計(jì),從而大程度地提升瀏覽體驗(yàn)。創(chuàng)新互聯(lián)從事“密山網(wǎng)站設(shè)計(jì)”,“密山網(wǎng)站推廣”以來(lái),每個(gè)客戶項(xiàng)目都認(rèn)真落實(shí)執(zhí)行。

  • 該對(duì)象沒(méi)有被其他對(duì)象引用

判定對(duì)象是否為垃圾的算法:

  • 引用計(jì)數(shù)算法,優(yōu)點(diǎn):執(zhí)行效率高,程序執(zhí)行受影響較?。蝗秉c(diǎn):無(wú)法檢測(cè)出循環(huán)引用的情況,容易導(dǎo)致內(nèi)存泄露
    • 通過(guò)判斷對(duì)象的引用數(shù)量來(lái)決定對(duì)象是否可以被回收
    • 每個(gè)對(duì)象實(shí)例都有一個(gè)引用計(jì)數(shù)器,被引用則+1,完成引用即引用結(jié)束則-1
    • 綜上,任何引用計(jì)數(shù)為0的對(duì)象實(shí)例就可以被當(dāng)作垃圾收集
  • 可達(dá)性分析算法(Java使用的算法)
    • 通過(guò)判斷對(duì)象的引用鏈?zhǔn)欠窨蛇_(dá)來(lái)決定對(duì)象是否可以被回收

可達(dá)性分析算法遍歷引用鏈如圖:
Java底層:GC相關(guān)

可以作為GC Root的對(duì)象:

  • 虛擬機(jī)棧中引用的對(duì)象(棧幀中的本地變量表)
  • 方法區(qū)中的常量引用的對(duì)象
  • 方法區(qū)中的類靜態(tài)屬性所引用的對(duì)象
  • 本地方法棧中JNI(Native)的引用對(duì)象
  • 活躍線程的引用對(duì)象,即線程對(duì)象

Java垃圾回收之回收算法

光有垃圾標(biāo)記算法還不行,JVM還需要有垃圾回收算法來(lái)將這些標(biāo)記為垃圾的對(duì)象給釋放回收掉。主要的回收算法有以下幾種:

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

  • 標(biāo)記:從根集合進(jìn)行掃描,對(duì)存活的對(duì)象進(jìn)行標(biāo)記
  • 清除:對(duì)堆內(nèi)存從頭到尾進(jìn)行線性遍歷,回收不可達(dá)對(duì)象內(nèi)存

Java底層:GC相關(guān)

缺點(diǎn):由于標(biāo)記 - 清除不需要進(jìn)行對(duì)象的移動(dòng),并且僅對(duì)不可達(dá)的對(duì)象進(jìn)行處理,因此使用該回收算法之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片。而內(nèi)存碎片過(guò)多可能會(huì)導(dǎo)致以后在程序運(yùn)行過(guò)程中,需要分配內(nèi)存給較大的對(duì)象時(shí),無(wú)法找到足夠大的連續(xù)內(nèi)存空間,從而不得不再次觸發(fā)垃圾回收工作,若依舊無(wú)法分配內(nèi)存的話就會(huì)觸發(fā)內(nèi)存溢出異常。

1.復(fù)制算法(Copying):

  • 將可用的內(nèi)存容量按一定比例劃分為兩塊或多塊,并將其中一塊或兩塊作為對(duì)象面,剩余的則作為空閑面
  • 對(duì)象在對(duì)象面上創(chuàng)建,當(dāng)對(duì)象面的內(nèi)存空間用完時(shí),會(huì)將存活的對(duì)象從對(duì)象面復(fù)制到空閑面中,接著清除該對(duì)象面中所有的對(duì)象

Java底層:GC相關(guān)

優(yōu)點(diǎn):解決內(nèi)存碎片化問(wèn)題,順序分配內(nèi)存,簡(jiǎn)單高效。該算法適用于對(duì)象存活率低的場(chǎng)景,所以普遍應(yīng)用在新生代中,因?yàn)樾律锏膶?duì)象存活率通常情況下只有10%左右

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

  • 標(biāo)記:從根集合進(jìn)行掃描,對(duì)存活的對(duì)象進(jìn)行標(biāo)記
  • 整理:移動(dòng)所有存活的對(duì)象,且按照內(nèi)存地址次序依次排列,然后將末端內(nèi)存地址以后的內(nèi)存全部回收

Java底層:GC相關(guān)

優(yōu)點(diǎn):避免了標(biāo)記 - 清除算法所帶來(lái)的內(nèi)存不連續(xù)性問(wèn)題,以及不需要像復(fù)制算法那樣需要設(shè)置兩塊內(nèi)存互換。該算法適用于對(duì)象存活率較高的場(chǎng)景,所以普遍應(yīng)用在老年代中,因?yàn)槔夏甏飳?duì)象存活率較高

4.分代收集算法(Generational Collector):

  • 實(shí)際是多種垃圾回收算法的組合拳,該算法對(duì)堆內(nèi)存進(jìn)行進(jìn)一步的劃分,按照對(duì)象生命周期的不同劃分區(qū)域以采用不同的垃圾回收算法。目的是提高JVM的回收效率,也是目前JVM使用的回收算法

在JDK7及之前的JVM版本共有三個(gè)分代,即新生代、老年代和永久代(注意,永久代不存在于堆中,而是存在于方法區(qū)):
Java底層:GC相關(guān)

而JDK8及以后的版本只有新生代和老年代:
Java底層:GC相關(guān)

分代收集算法的GC分為兩種:

  • Minor GC,發(fā)生在新生代中的垃圾收集工作,采用的是復(fù)制算法
  • Full GC,當(dāng)觸發(fā)老年代的垃圾回收的時(shí)候通常也會(huì)伴隨著對(duì)新生代堆內(nèi)存的回收,即對(duì)整個(gè)堆進(jìn)行垃圾回收,這便是所謂的FullGC

新生代用于盡可能快速地收集掉那些生命周期短的對(duì)象,新生代分為兩個(gè)區(qū):

  • Eden區(qū):新創(chuàng)建的對(duì)象通常存放在這個(gè)區(qū)域,如果新創(chuàng)建的對(duì)象太大放不進(jìn)該區(qū)域則會(huì)放進(jìn)Survivor區(qū)或老年代中
  • 兩個(gè)Survivor區(qū),該區(qū)域又分為to和from區(qū),至于誰(shuí)是to區(qū)誰(shuí)是from區(qū)則不是固定的,而是會(huì)隨著GC互相轉(zhuǎn)換

Java底層:GC相關(guān)

對(duì)象如何晉升到老年代:

  • 新生代里的對(duì)象每經(jīng)歷一次Minor GC并且存活,其年齡就會(huì)+1,當(dāng)經(jīng)歷一定Minor GC次數(shù)依然存活的對(duì)象就會(huì)晉升到老年代,默認(rèn)是15歲,即默認(rèn)經(jīng)歷了15次Minor GC依舊存活的對(duì)象會(huì)被放到老年代
  • Survivor區(qū)中存放不下的對(duì)象會(huì)被直接放到老年代
  • 新生成的大對(duì)象會(huì)被直接放到老年代(通過(guò)參數(shù):-XX:+PreetenuerSizeThreshold 設(shè)置)

常用的調(diào)優(yōu)參數(shù):

  • -XX:SurvivorRatio:Eden和Survivor的比值,默認(rèn)8:1
  • -XX:NewRatio:老年代和新生代內(nèi)存大小的比例
  • -XX:MaxTenuringThreshold:對(duì)象從新生代晉升到老年代經(jīng)過(guò)GC次數(shù)的最大閾值

綜上,老年代用于存放生命周期較長(zhǎng)的對(duì)象,老年代采用的是標(biāo)記 - 整理算法。

Full GC和Major GC:

  • Major GC通常是跟full GC是等價(jià)的,即收集整個(gè)GC堆。但因?yàn)镠otSpot VM發(fā)展了這么多年,外界對(duì)各種名詞的解讀已經(jīng)完全混亂了,當(dāng)有人說(shuō)“major GC”的時(shí)候一定要問(wèn)清楚他想要指的是上面的full GC還是僅僅針對(duì)老年代的 GC
  • Full GC比Minor GC慢,但執(zhí)行頻率低

觸發(fā)Full GC的條件:

  • 老年代空間不足
  • 永久代空間不足(JDK7及之前的版本)
  • 使用CMS GC時(shí)出現(xiàn)promotion failed,concurrent mode failure
  • Minor GC晉升到老年代的平均大小大于老年代的剩余空間
  • 在代碼里調(diào)用System.gc(),該方法只能作為提醒,具體是否觸發(fā)Full GC還得看JVM
  • 使用RMI來(lái)進(jìn)行RPC或管理的JDK應(yīng)用,每小時(shí)執(zhí)行1次Full GC

注:promotion failed是在進(jìn)行Minor GC時(shí),survivor space放不下、對(duì)象只能放入老年代,而此時(shí)老年代也放不下造成的;concurrent mode failure是在執(zhí)行CMS GC的過(guò)程中同時(shí)有對(duì)象要放入老年代,而此時(shí)老年代空間不足造成的。


Java垃圾回收之新生代垃圾收集器

在了解垃圾收集器之前,我們需要知道一個(gè)概念“Stop-the-World”:

  • 該單詞的含義即:JVM由于要執(zhí)行GC而停止了應(yīng)用程序的執(zhí)行
  • 并且任何一個(gè)GC算法中都會(huì)發(fā)生
  • 實(shí)際上多數(shù)GC優(yōu)化就是通過(guò)減少Stop-the-World發(fā)生的時(shí)間來(lái)提高程序性能

除此之外,我們需要知道什么是Safepoint:

  • 分析過(guò)程中對(duì)象引用關(guān)系不會(huì)發(fā)生變化的點(diǎn),即安全點(diǎn)(Safepoint)。因?yàn)镴VM不能隨隨便便就發(fā)生Stop-the-World,而是到一個(gè)相對(duì)安全的點(diǎn)才會(huì)發(fā)生
  • 產(chǎn)生Safepoint的地方:方法調(diào)用、循環(huán)跳轉(zhuǎn)、異常跳轉(zhuǎn)等等
  • 安全點(diǎn)數(shù)量得適中

JVM的運(yùn)行模式:

  • Server:?jiǎn)?dòng)速度較慢,但是啟動(dòng)完成進(jìn)入穩(wěn)定期之后的運(yùn)行速度比Client快,因?yàn)镾erver模式采用的是重量級(jí)的JVM,有比Client模式更多的優(yōu)化
  • Client:?jiǎn)?dòng)速度較快,采用的是輕量級(jí)的JVM

各垃圾收集器之間的聯(lián)系,即可以搭配使用關(guān)系:
Java底層:GC相關(guān)

Serial收集器(啟動(dòng)參數(shù):-XX:+UseSerialGC,采用復(fù)制算法):

  • 單線程收集,進(jìn)行垃圾收集時(shí),必須暫停所有工作線程
  • 簡(jiǎn)單高效,是Client模式下默認(rèn)的新生代收集器
    Java底層:GC相關(guān)

ParNew收集器(啟動(dòng)參數(shù):-XX:+UseParNewGC,采用復(fù)制算法):

  • 除了是采用多線程進(jìn)行垃圾回收外,其余行為、特點(diǎn)與Serial收集器一樣;是Server模式下首選的年輕代垃圾收集器
  • 單核執(zhí)行效率不如Serial,需要在多核環(huán)境下執(zhí)行才有優(yōu)勢(shì)
  • 該收集器默認(rèn)開(kāi)啟的垃圾收集線程數(shù)與CPU核心數(shù)量相同
    Java底層:GC相關(guān)

Parallel Scavenge收集器(啟動(dòng)參數(shù):-XX:+UseParallelGC,采用復(fù)制算法):

  • 該收集器也是多線程的,只不過(guò)比起之前所介紹的收集器關(guān)注用戶線程停頓時(shí)間,該收集器更關(guān)注系統(tǒng)的吞吐量
    • 吞吐量 = 運(yùn)行用戶代碼時(shí)間 / (運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)
  • 同樣在多核環(huán)境下執(zhí)行才有優(yōu)勢(shì),Server模式下默認(rèn)的新生代收集器
    Java底層:GC相關(guān)

Java垃圾回收之老年代垃圾收集器

Serial Old收集器(啟動(dòng)參數(shù):-XX:+UseSerialOldGC,采用標(biāo)記 - 整理算法):

  • 該收集器是Serial收集器的老年代版本,也是單線程收集,進(jìn)行垃圾收集時(shí),必須暫停所有工作線程
  • 簡(jiǎn)單高效,Client模式下默認(rèn)的老年代收集器
    Java底層:GC相關(guān)

Parallel Old收集器(啟動(dòng)參數(shù):-XX:+UseParallelOldGC,采用標(biāo)記 - 整理算法):

  • 該收集器是Parallel Scavenge收集器的老年代版本,也是多線程收集,同樣是吞吐量?jī)?yōu)先
  • 通常配合新生代的Parallel Scavenge收集器使用
    Java底層:GC相關(guān)

CMS收集器(啟動(dòng)參數(shù):-XX:+UseConcMarkSweepGC,采用標(biāo)記 - 清除算法):

  • 多線程收集,停頓時(shí)間優(yōu)先,通常配合新生代的ParNew收集器使用

CMS收集器收集流程:

  1. 初始標(biāo)記:會(huì)觸發(fā)stop-the-world,但是停頓時(shí)間很短
  2. 并發(fā)標(biāo)記:并發(fā)追溯標(biāo)記,程序不會(huì)停頓
  3. 并發(fā)預(yù)清理:查找執(zhí)行并發(fā)標(biāo)記階段從新生代晉升到老年代的對(duì)象
  4. 重新標(biāo)記:暫停虛擬機(jī),掃描CMS堆中的剩余對(duì)象
  5. 并發(fā)清理:清理垃圾對(duì)象,程序不會(huì)停頓
  6. 并發(fā)重置:重置CMS收集器的數(shù)據(jù)結(jié)構(gòu)

CMS收集器圖示:
Java底層:GC相關(guān)

G1收集器(啟動(dòng)參數(shù):-XX:+UseG1GC,采用復(fù)制 + 標(biāo)記 - 整理算法):

  • 該收集同時(shí)用于新生代和老年代,該收集器的目標(biāo)在于替換掉CMS,并且采取了某些不同的方式跨越了新生代和老年代的邊界
  • 將整個(gè)Java堆內(nèi)存劃分成多個(gè)大小相等的Region,即新生代和老年代不再是物理隔離的了
  • G1收集器全稱為Garbage First,該收集器的特點(diǎn)如下:
    • 并行和并發(fā)
    • 分代收集
    • 空間整合
    • 可預(yù)測(cè)的停頓

Java底層:GC相關(guān)


Java垃圾回收之常見(jiàn)面試題

1.Object的finalize()方法的作用是否與C++的析構(gòu)函數(shù)作用相同:

  • 與C++的析構(gòu)函數(shù)不同,析構(gòu)函數(shù)調(diào)用確定,而finalize()方法是不確定的,因?yàn)閒inalize()方法在對(duì)象被GC回收時(shí)調(diào)用
  • 將未被引用的對(duì)象放置于F-Queue隊(duì)列
  • 該方法執(zhí)行隨時(shí)可能會(huì)被終止
  • 它的設(shè)計(jì)目的是保證對(duì)象在被垃圾收集前完成特定資源的回收或給予對(duì)象最后一次重生機(jī)會(huì)等

示例代碼:

package com.example.demo.gc;

/**
 * @author 01
 * @date 2019-07-18
 **/
public class Finalization {

    public static Finalization finalization;

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalize");
        finalization = this;
    }

    public static void main(String[] args) {
        Finalization f = new Finalization();
        System.out.println("First print: " + f);
        f = null;
        System.gc();
        System.out.println("Second print: " + f);
        System.out.println(f.finalization);
    }
}

執(zhí)行結(jié)果:
Java底層:GC相關(guān)

從執(zhí)行結(jié)果可以看到,F(xiàn)inalization對(duì)象被GC回收時(shí)finalize()方法會(huì)被調(diào)用,finalize()方法里將當(dāng)前對(duì)象this賦值給了靜態(tài)屬性finalization實(shí)現(xiàn)了對(duì)象的“重生”,所以在GC之后依舊能打印到該對(duì)象的地址信息

注:finalize是個(gè)不太可控的方法因此并不常用,并且在JDK9+版本被標(biāo)注為過(guò)時(shí)方法

2.Java中的強(qiáng)引用,軟引用,弱引用及虛引用有什么用:

  • 強(qiáng)引用(Strong reference):

    所謂強(qiáng)引用,就是我們最常見(jiàn)的普通對(duì)象引用,只要還有強(qiáng)引用指向一個(gè)對(duì)象,就能表明對(duì)象還“活著”,垃圾收集器不會(huì)碰這種對(duì)象。對(duì)于一個(gè)普通的對(duì)象,如果沒(méi)有其他的引用關(guān)系,只要超過(guò)了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為 null,就是可以被垃圾收集的了,當(dāng)然具體回收時(shí)機(jī)還是要看垃圾收集策略??偨Y(jié):

    • 最普遍的引用,例:Object obj = new Object();
    • JVM寧可拋出OutOfMemoryError終止程序也不會(huì)回收具有強(qiáng)引用的對(duì)象
    • 通過(guò)將對(duì)象設(shè)置為null來(lái)弱化引用,使其被回收
  • 軟引用(Soft reference):

    是一種相對(duì)強(qiáng)引用弱化一些的引用,可以讓對(duì)象豁免一些垃圾收集,只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象。JVM 會(huì)確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對(duì)象。軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存,如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。總結(jié):

    • 對(duì)象處在有用但非必須的狀態(tài)
    • 只有當(dāng)內(nèi)存空間不足時(shí),GC會(huì)回收該引用的對(duì)象內(nèi)存
    • 軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存
    • 可以配合引用對(duì)象使用(ReferenceQueue)
  • 弱引用(Weak reference):

    弱引用并不能使對(duì)象豁免垃圾收集,僅僅是提供一種訪問(wèn)在弱引用狀態(tài)下對(duì)象的途徑。這就可以用來(lái)構(gòu)建一種沒(méi)有特定約束的關(guān)系,比如,維護(hù)一種非強(qiáng)制性的映射關(guān)系,如果試圖獲取時(shí)對(duì)象還在,就使用它,否則重現(xiàn)實(shí)例化。它同樣是很多緩存實(shí)現(xiàn)的選擇??偨Y(jié):

    • 用于描述非必須的對(duì)象,比軟引用更弱一些
    • 發(fā)生GC時(shí)就會(huì)被回收掉,不過(guò)被回收的概率也不大,因?yàn)镚C線程優(yōu)先級(jí)比較低
    • 適用于引用偶爾被使用且不影響垃圾收集的對(duì)象
    • 可以配合引用對(duì)象使用(ReferenceQueue)
  • 虛引用(Phantom reference),也被稱為幻象引用:

    對(duì)于虛引用,你不能通過(guò)它訪問(wèn)對(duì)象。虛引用僅僅是提供了一種確保對(duì)象被 finalize 以后,做某些事情的機(jī)制,比如,通常用來(lái)做所謂的 Post-Mortem 清理機(jī)制,例如 Java 平臺(tái)自身 Cleaner 機(jī)制等,也有人利用幻象引用監(jiān)控對(duì)象的創(chuàng)建和銷毀??偨Y(jié):

    • 不會(huì)決定對(duì)象的生命周期
    • 虛引用的對(duì)象任何時(shí)候都可能被垃圾收集器回收,就像是沒(méi)有引用的對(duì)象一樣
    • 虛引用通常用來(lái)跟蹤對(duì)象被垃圾收集器回收的活動(dòng),起哨兵作用
    • 與軟引用和弱引用不同的是,該引用必須與引用對(duì)列(ReferenceQueue)聯(lián)合使用

軟引用代碼示例:

// 強(qiáng)引用
String str = new String("abc");
// 轉(zhuǎn)換為軟引用
SoftReference softReference = new SoftReference<>(str);

弱引用代碼示例:

String str = new String("abc");
// 弱引用
WeakReference weakReference = new WeakReference<>(str);

虛引用代碼示例:

String str = new String("abc");
// 引用隊(duì)列
ReferenceQueue queue = new ReferenceQueue<>();
// 轉(zhuǎn)換為虛引用
PhantomReference phantomReference = new PhantomReference<>(str, queue);
// GC在回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)該對(duì)象存在虛引用,那么在回收之前會(huì)先將該對(duì)象的虛引用添加到與該對(duì)象關(guān)聯(lián)的引用隊(duì)列中;程序代碼可以通過(guò)判斷引用隊(duì)列是否已加入虛引用來(lái)得知被引用的對(duì)象是否已經(jīng)被回收

引用隊(duì)列(ReferenceQueue):

  • ReferenceQueue無(wú)實(shí)際的存儲(chǔ)結(jié)構(gòu),其存儲(chǔ)邏輯依賴于內(nèi)部節(jié)點(diǎn)之間的關(guān)系來(lái)表達(dá)
  • 存儲(chǔ)關(guān)聯(lián)的且被GC后的軟引用,弱引用以及虛引用

引用強(qiáng)度關(guān)系:

  • 強(qiáng)引用 > 軟引用 > 弱引用 > 虛引用

Java底層:GC相關(guān)

下面流程圖簡(jiǎn)單總結(jié)了對(duì)象生命周期和不同可達(dá)性狀態(tài),以及不同狀態(tài)可能的改變關(guān)系:
Java底層:GC相關(guān)

上圖的具體狀態(tài),實(shí)際是 Java 定義的不同可達(dá)性級(jí)別(reachability level),在之前也說(shuō)過(guò)判斷對(duì)象可達(dá)性,是 JVM 垃圾收集器決定如何處理對(duì)象的一部分考慮。可達(dá)性具體含義如下:

  • 強(qiáng)可達(dá)(Strongly Reachable),就是當(dāng)一個(gè)對(duì)象可以有一個(gè)或多個(gè)線程可以不通過(guò)各種引用訪問(wèn)到的情況。比如,我們新創(chuàng)建一個(gè)對(duì)象,那么創(chuàng)建它的線程對(duì)它就是強(qiáng)可達(dá)。
  • 軟可達(dá)(Softly Reachable),就是當(dāng)我們只能通過(guò)軟引用才能訪問(wèn)到對(duì)象的狀態(tài)。
  • 弱可達(dá)(Weakly Reachable),類似前面提到的,就是無(wú)法通過(guò)強(qiáng)引用或者軟引用訪問(wèn),只能通過(guò)弱引用訪問(wèn)時(shí)的狀態(tài)。這是十分臨近 finalize 狀態(tài)的時(shí)機(jī),當(dāng)弱引用被清除的時(shí)候,就符合 finalize 的條件了。
  • 幻象可達(dá)(Phantom Reachable),上面流程圖已經(jīng)很直觀了,就是沒(méi)有強(qiáng)、軟、弱引用關(guān)聯(lián),并且 finalize 過(guò)了,只有幻象引用指向這個(gè)對(duì)象的時(shí)候。
  • 當(dāng)然,還有一個(gè)最后的狀態(tài),就是不可達(dá)(unreachable),意味著對(duì)象可以被清除了。

各引用包裝類的繼承關(guān)系圖:
Java底層:GC相關(guān)


下面我們來(lái)用一個(gè)例子演示引用包裝對(duì)象及引用隊(duì)列的使用,首先定義一個(gè)普通的類,并且實(shí)現(xiàn)finalize方法以便我們?cè)跍y(cè)試時(shí)可以看到該對(duì)象是否被GC回收了:

package com.example.demo.gc;

/**
 * @author 01
 * @date 2019-07-18
 **/
public class NormalObject {

    public String name;

    public NormalObject(String name) {
        this.name = name;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalizing obj: " + name);
    }
}

然后定義一個(gè)WeakReference的子類,目的是擴(kuò)展name屬性,以便我們?cè)跍y(cè)試時(shí)能夠得知是哪個(gè)對(duì)象的引用對(duì)象:

package com.example.demo.gc;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

/**
 * @author 01
 * @date 2019-07-18
 **/
public class NormalObjectWeakReference extends WeakReference {

    public String name;

    public NormalObjectWeakReference(NormalObject referent, ReferenceQueue queue) {
        super(referent, queue);
        this.name = referent.name;
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("finalizing NormalObjectWeakReference: " + name);
    }
}

最后編寫一個(gè)測(cè)試類:

package com.example.demo.gc;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 01
 * @date 2019-07-18
 **/
public class ReferenceQueueTests {
    // 引用隊(duì)列
    private static ReferenceQueue queue = new ReferenceQueue<>();

    /**
     * 檢查引用隊(duì)列里有沒(méi)有引用對(duì)象,有的話則打印相關(guān)信息
     */
    private static void checkQueue() {
        Reference reference;
        while ((reference = queue.poll()) != null) {
            // 存在于引用隊(duì)列中的引用對(duì)象
            System.out.println("In Queue: " + ((NormalObjectWeakReference) (reference)).name);
            // 獲取引用的對(duì)象實(shí)例
            System.out.println("reference object: " + reference.get());
        }
    }

    public static void main(String[] args) throws InterruptedException {
        List> weakReferenceList = new ArrayList<>();
        // 創(chuàng)建引用對(duì)象
        for (int i = 0; i < 3; i++) {
            NormalObject normalObject = new NormalObject("Weak-" + i);
            NormalObjectWeakReference reference = new NormalObjectWeakReference(normalObject, queue);
            weakReferenceList.add(reference);
            System.out.println("Create weak: " + reference);
        }

        System.out.println("\nbefore gc ------");
        checkQueue();

        System.out.println("\ngc ing... ------");
        System.gc();
        // 讓線程休眠一會(huì),以保gc能夠正常執(zhí)行完畢
        Thread.sleep(1000);

        System.out.println("\nafter gc ------");
        checkQueue();
    }
}

運(yùn)行結(jié)果:
Java底層:GC相關(guān)

可以看到在GC執(zhí)行之前調(diào)用checkQueue方法沒(méi)有打印任何信息,因?yàn)榇藭r(shí)引用隊(duì)列中沒(méi)有任何引用對(duì)象。而當(dāng)GC執(zhí)行之后,引用隊(duì)列中就被添加了與之相關(guān)聯(lián)的引用對(duì)象,所以就能夠打印出引用對(duì)象的相關(guān)信息


GC相關(guān)參考文章:

  • JVM層GC調(diào)優(yōu)(上)
  • JVM層GC調(diào)優(yōu)(下)

新聞名稱:Java底層:GC相關(guān)
分享鏈接:http://weahome.cn/article/ggpcgs.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部