新聞中心
在 JVM 中,有兩個(gè)非常重要的知識(shí)點(diǎn),一個(gè)是 JVM 的內(nèi)存布局(JVM 運(yùn)行時(shí)的數(shù)據(jù)區(qū)域),另一個(gè)就是垃圾回收。而垃圾回收中又有兩個(gè)重要的知識(shí)點(diǎn),一個(gè)是如何確定 JVM 中的垃圾對(duì)象,另一個(gè)是使用不同的垃圾收集器進(jìn)行垃圾回收。而本篇要討論的是前者,后面的內(nèi)容咱們下一篇再聊。

垃圾(死亡)對(duì)象的判定有兩種常用的算法:引用計(jì)數(shù)器算法和可達(dá)性分析算法。
1.引用計(jì)數(shù)器算法
引用計(jì)數(shù)算法(Reference Counting) 屬于垃圾收集器的早期實(shí)現(xiàn)算法了,它指的是在創(chuàng)建對(duì)象時(shí)關(guān)聯(lián)一個(gè)與之相對(duì)應(yīng)的計(jì)數(shù)器,當(dāng)此對(duì)象被使用時(shí)加 1,相反銷毀時(shí) -1。當(dāng)此計(jì)數(shù)器為 0 時(shí),則表示此對(duì)象未使用,可以被垃圾收集器回收。
引用計(jì)數(shù)算法的優(yōu)缺點(diǎn)很明顯,其優(yōu)點(diǎn)是垃圾回收比較及時(shí),實(shí)時(shí)性比較高,只要對(duì)象計(jì)數(shù)器為 0,則可以直接進(jìn)行回收操作;而缺點(diǎn)是無(wú)法解決循環(huán)引用的問(wèn)題,比如以下代碼:
public class RefCounterTest {
// 對(duì)象 A
static class RefObjectA {
private RefObjectB refObjectB;
public void setRefObjectB(RefObjectB refObjectB) {
this.refObjectB = refObjectB;
}
}
// 對(duì)象 B
static class RefObjectB {
private RefObjectA refObjectA;
public void setRefObjectA(RefObjectA refObjectA) {
this.refObjectA = refObjectA;
}
}
// 測(cè)試代碼
public static void main(String[] args) {
RefObjectA objectA = new RefObjectA();
RefObjectB objectB = new RefObjectB();
objectA.setRefObjectB(objectB);
objectB.setRefObjectA(objectA);
objectA = null;
objectB = null;
}
}如以上代碼所示,即使是將 main 方法中的 objectA 和 objectB 都設(shè)置為 null,也就是這兩個(gè)對(duì)象都徹底不使用了,但是因?yàn)槎叽嬖谙嗷ヒ玫年P(guān)系,所以它們所對(duì)應(yīng)的對(duì)象計(jì)數(shù)器不為 0,這樣循環(huán)引用導(dǎo)致垃圾數(shù)據(jù)無(wú)法被清除的事件就產(chǎn)生了。
2.可達(dá)性分析算法
可達(dá)性分析算法(Reachability Analysis) 是目前主流虛擬機(jī)中,使用最廣泛的判斷垃圾對(duì)象的實(shí)現(xiàn)算法,它指的是從對(duì)象的起點(diǎn)(GC Roots)開始向下搜索,如果對(duì)象到 GC Roots 沒(méi)有任何引用鏈相連時(shí),也就是說(shuō)此對(duì)象到 GC Roots 不可達(dá)時(shí),則表示此對(duì)象可以被垃圾回收器所回收,如下圖所示:
在 Java 語(yǔ)言中,可作為根節(jié)點(diǎn)(GC Roots)的對(duì)象有以下 4 類:
- Java 虛擬機(jī)棧中的引用對(duì)象,也就是 Java 虛擬機(jī)棧幀中,本地變量表所存儲(chǔ)的(引用)對(duì)象。在 Java 虛擬機(jī)棧幀中存儲(chǔ)的對(duì)象都是將來(lái)執(zhí)行時(shí),要使用的對(duì)象,所以和引用對(duì)象相關(guān)的對(duì)象都不能被回收;
- 本地方法棧中的引用對(duì)象和 Java 虛擬機(jī)棧中的引用對(duì)象類似,也不能被回收;
- 方法區(qū)中類靜態(tài)屬性引用的對(duì)象也可以作為 GC Roots;
- 方法區(qū)中常量引用的對(duì)象也可以作為 GC Roots。因?yàn)槌A渴潜4嬖诔A砍刂械?,屬于全局可使用的?duì)象,所以也能作為 GC Roots。
3.有關(guān)“引用”
不管是引用計(jì)數(shù)法還是可達(dá)性分析算法都與對(duì)象的“引用”有關(guān),這說(shuō)明對(duì)象的引用決定了對(duì)象的生死,而 Java 中的引用也比較復(fù)雜,它從 JDK 1.2 之后,(引用)分成了以下 4 種類型:
- 強(qiáng)引用:在代碼中普遍存在的,類似 Object obj = new Object() 這類引用,只要強(qiáng)引用還在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象;
- 軟引用:是一種相對(duì)強(qiáng)引用弱化一些的引用,可以讓對(duì)象豁免一些垃圾收集,只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象,JVM 會(huì)確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對(duì)象;
- 弱引用:非必需對(duì)象,但它的強(qiáng)度比軟引用更弱,被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾收集發(fā)生之前;
- 虛引用:也稱為幽靈引用或幻影引用,是最弱的一種引用關(guān)系,無(wú)法通過(guò)虛引用來(lái)獲取一個(gè)對(duì)象實(shí)例,為對(duì)象設(shè)置虛引用的目的只有一個(gè),就是當(dāng)著個(gè)對(duì)象被收集器回收時(shí)收到一條系統(tǒng)通知。
總結(jié)
垃圾對(duì)象的判定有兩種常用的算法:引用計(jì)數(shù)器算法和可達(dá)性分析算法。其中引用計(jì)數(shù)器算法實(shí)現(xiàn)簡(jiǎn)單、運(yùn)行高效,但是存在循環(huán)引用的問(wèn)題,所以主流的虛擬機(jī)使用的都是可達(dá)性分析算法,可達(dá)性分析算法是從對(duì)象的根節(jié)點(diǎn) GC Roots 向下搜索,如果根節(jié)點(diǎn)相連就是正常的對(duì)象,否則為垃圾對(duì)象可以被垃圾回收器回收。
標(biāo)題名稱:面試官:JVM如何確定死亡對(duì)象?
本文URL:http://www.dlmjj.cn/article/djcggje.html


咨詢
建站咨詢
