可達(dá)性算法、Java引用 詳解

在堆里存放著幾乎多有的java對象實例堰酿,垃圾搜集器在對堆進(jìn)行回收之前,第一件事情就是確定這些對象之中哪些還“存活”著(即通過任何途徑都無法使用的對象)张足。

一触创、可達(dá)性分析算法

在Java中,是通過可達(dá)性分析(Reachability Analysis)來判定對象是否存活的为牍。該算法的基本思路就是通過一些被稱為引用鏈(GC Roots)的對象作為起點哼绑,從這些節(jié)點開始向下搜索,搜索走過的路徑被稱為(Reference Chain)吵聪,當(dāng)一個對象到GC Roots沒有任何引用鏈相連時(即從GC Roots節(jié)點到該節(jié)點不可達(dá))凌那,則證明該對象是不可用的。

可達(dá)性分析算法判斷對象是否可以回收

如上圖所示吟逝,object1~object4對GC Root都是可達(dá)的帽蝶,說明不可被回收,object5和object6對GC Root節(jié)點不可達(dá)块攒,說明其可以被回收励稳。
在Java中,可作為GC Root的對象包括以下幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對象
  • 方法區(qū)中類靜態(tài)屬性引用的對象
  • 方法區(qū)中常量引用的對象
  • 本地方法棧中JNI(即一般說的Native方法)引用的對象

二囱井、finalize()方法最終判定對象是否存活

即使在可達(dá)性分析算法中不可達(dá)的對象驹尼,也并非是“非死不可”的,這時候它們暫時處于“緩刑”階段庞呕,要真正宣告一個對象死亡新翎,至少要經(jīng)歷再次標(biāo)記過程。
標(biāo)記的前提是對象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈住练。
1. 第一次標(biāo)記并進(jìn)行一次篩選地啰。
篩選的條件是此對象是否有必要執(zhí)行finalize()方法。
當(dāng)對象沒有覆蓋finalize方法讲逛,或者finzlize方法已經(jīng)被虛擬機(jī)調(diào)用過亏吝,虛擬機(jī)將這兩種情況都視為“沒有必要執(zhí)行”,對象被回收盏混。
2. 第二次標(biāo)記
如果這個對象被判定為有必要執(zhí)行finalize()方法蔚鸥,那么這個對象將會被放置在一個名為:F-Queue的隊列之中,并在稍后由一條虛擬機(jī)自動建立的许赃、低優(yōu)先級的Finalizer線程去執(zhí)行止喷。這里所謂的“執(zhí)行”是指虛擬機(jī)會觸發(fā)這個方法,但并不承諾會等待它運行結(jié)束混聊。這樣做的原因是启盛,如果一個對象finalize()方法中執(zhí)行緩慢,或者發(fā)生死循環(huán)(更極端的情況),將很可能會導(dǎo)致F-Queue隊列中的其他對象永久處于等待狀態(tài)僵闯,甚至導(dǎo)致整個內(nèi)存回收系統(tǒng)崩潰卧抗。
Finalize()方法是對象脫逃死亡命運的最后一次機(jī)會,稍后GC將對F-Queue中的對象進(jìn)行第二次小規(guī)模標(biāo)記鳖粟,如果對象要在finalize()中成功拯救自己----只要重新與引用鏈上的任何的一個對象建立關(guān)聯(lián)即可社裆,譬如把自己賦值給某個類變量或?qū)ο蟮某蓡T變量,那在第二次標(biāo)記時它將移除出“即將回收”的集合向图。如果對象這時候還沒逃脫泳秀,那基本上它就真的被回收了。

三榄攀、Java引用

從可達(dá)性算法中可以看出嗜傅,判斷對象是否可達(dá)時,與“引用”有關(guān)檩赢。那么什么情況下可以說一個對象被引用吕嘀,引用到底代表什么?
在JDK1.2之后贞瞒,Java對引用的概念進(jìn)行了擴(kuò)充偶房,可以將引用分為以下四類:

  • 強(qiáng)引用(Strong Reference)
  • 軟引用(Soft Reference)
  • 弱引用(Weak Reference)
  • 虛引用(Phantom Reference)

這四種引用從上到下,依次減弱

3.1 強(qiáng)引用

強(qiáng)引用就是指在程序代碼中普遍存在的军浆,類似Object obj = new Object()這類似的引用棕洋,只要強(qiáng)引用在,垃圾搜集器永遠(yuǎn)不會搜集被引用的對象乒融。也就是說掰盘,寧愿出現(xiàn)內(nèi)存溢出,也不會回收這些對象赞季。

3.2 軟引用

軟引用是用來描述一些有用但并不是必需的對象愧捕,在Java中用java.lang.ref.SoftReference類來表示。對于軟引用關(guān)聯(lián)著的對象碟摆,只有在內(nèi)存不足的時候JVM才會回收該對象。因此叨橱,這一點可以很好地用來解決OOM的問題典蜕,并且這個特性很適合用來實現(xiàn)緩存:比如網(wǎng)頁緩存、圖片緩存等罗洗。

import java.lang.ref.SoftReference;
 
public class Main {
    public static void main(String[] args) {
         
        SoftReference<String> sr = new SoftReference<String>(new String("hello"));
        System.out.println(sr.get());
    }
}

3.3 弱引用

弱引用也是用來描述非必需對象的愉舔,當(dāng)JVM進(jìn)行垃圾回收時,無論內(nèi)存是否充足伙菜,都會回收被弱引用關(guān)聯(lián)的對象轩缤。在java中,用java.lang.ref.WeakReference類來表示。下面是使用示例:

import java.lang.ref.WeakReference;
 
public class Main {
    public static void main(String[] args) {
     
        WeakReference<String> sr = new WeakReference<String>(new String("hello"));
         
        System.out.println(sr.get());
        System.gc();                //通知JVM的gc進(jìn)行垃圾回收
        System.out.println(sr.get());
    }
}

3.4 虛引用

虛引用和前面的軟引用火的、弱引用不同壶愤,它并不影響對象的生命周期。在java中用java.lang.ref.PhantomReference類表示馏鹤。如果一個對象與虛引用關(guān)聯(lián)征椒,則跟沒有引用與之關(guān)聯(lián)一樣,在任何時候都可能被垃圾回收器回收湃累。
要注意的是勃救,虛引用必須和引用隊列關(guān)聯(lián)使用,當(dāng)垃圾回收器準(zhǔn)備回收一個對象時治力,如果發(fā)現(xiàn)它還有虛引用蒙秒,就會把這個虛引用加入到與之 關(guān)聯(lián)的引用隊列中。程序可以通過判斷引用隊列中是否已經(jīng)加入了虛引用宵统,來了解被引用的對象是否將要被垃圾回收晕讲。如果程序發(fā)現(xiàn)某個虛引用已經(jīng)被加入到引用隊列,那么就可以在所引用的對象的內(nèi)存被回收之前采取必要的行動榜田。

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;
 
public class Main {
    public static void main(String[] args) {
        ReferenceQueue<String> queue = new ReferenceQueue<String>();
        PhantomReference<String> pr = new PhantomReference<String>(new String("hello"), queue);
        System.out.println(pr.get());
    }
}

3.5 軟引用和弱引用進(jìn)一步說明

在SoftReference類中益兄,有三個方法,兩個構(gòu)造方法和一個get方法(WekReference類似):

public class SoftReference<T> extends Reference<T> {

    /**
     * Timestamp clock, updated by the garbage collector
     */
    static private long clock;

    /**
     * Timestamp updated by each invocation of the get method.  The VM may use
     * this field when selecting soft references to be cleared, but it is not
     * required to do so.
     */
    private long timestamp;

    /**
     * Creates a new soft reference that refers to the given object.  The new
     * reference is not registered with any queue.
     *
     * @param referent object the new soft reference will refer to
     */
    public SoftReference(T referent) {
        super(referent);
        this.timestamp = clock;
    }

    /**
     * Creates a new soft reference that refers to the given object and is
     * registered with the given queue.
     *
     * @param referent object the new soft reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     *
     */
    public SoftReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
        this.timestamp = clock;
    }

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    public T get() {
        T o = super.get();
        if (o != null && this.timestamp != clock)
            this.timestamp = clock;
        return o;
    }

}

get方法用來獲取與軟引用關(guān)聯(lián)的對象的引用箭券,如果該對象被回收了净捅,則返回null。

在使用軟引用和弱引用的時候辩块,我們可以顯示地通過System.gc()來通知JVM進(jìn)行垃圾回收蛔六,但是要注意的是,雖然發(fā)出了通知废亭,JVM不一定會立刻執(zhí)行国章,也就是說這句是無法確保此時JVM一定會進(jìn)行垃圾回收的。

3.6 虛引用進(jìn)一步說明:

虛引用中有一個構(gòu)造函數(shù)豆村,可以看出液兽,其必須和一個引用隊列一起存在。get()方法永遠(yuǎn)返回null掌动,因為虛引用永遠(yuǎn)不可達(dá)四啰。

public class PhantomReference<T> extends Reference<T> {

    /**
     * Returns this reference object's referent.  Because the referent of a
     * phantom reference is always inaccessible, this method always returns
     * <code>null</code>.
     *
     * @return  <code>null</code>
     */
    public T get() {
        return null;
    }

    /**
     * Creates a new phantom reference that refers to the given object and
     * is registered with the given queue.
     *
     * <p> It is possible to create a phantom reference with a <tt>null</tt>
     * queue, but such a reference is completely useless: Its <tt>get</tt>
     * method will always return null and, since it does not have a queue, it
     * will never be enqueued.
     *
     * @param referent the object the new phantom reference will refer to
     * @param q the queue with which the reference is to be registered,
     *          or <tt>null</tt> if registration is not required
     */
    public PhantomReference(T referent, ReferenceQueue<? super T> q) {
        super(referent, q);
    }
}

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市粗恢,隨后出現(xiàn)的幾起案子柑晒,更是在濱河造成了極大的恐慌,老刑警劉巖眷射,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件匙赞,死亡現(xiàn)場離奇詭異佛掖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)涌庭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門芥被,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人脾猛,你說我怎么就攤上這事撕彤。” “怎么了猛拴?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵羹铅,是天一觀的道長。 經(jīng)常有香客問我愉昆,道長职员,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任跛溉,我火速辦了婚禮焊切,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘芳室。我一直安慰自己专肪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布堪侯。 她就那樣靜靜地躺著嚎尤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伍宦。 梳的紋絲不亂的頭發(fā)上芽死,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音次洼,去河邊找鬼关贵。 笑死,一個胖子當(dāng)著我的面吹牛卖毁,可吹牛的內(nèi)容都是我干的揖曾。 我是一名探鬼主播,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼亥啦,長吁一口氣:“原來是場噩夢啊……” “哼炭剪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起禁悠,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤念祭,失蹤者是張志新(化名)和其女友劉穎兑宇,沒想到半個月后碍侦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年瓷产,在試婚紗的時候發(fā)現(xiàn)自己被綠了站玄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡濒旦,死狀恐怖株旷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情尔邓,我是刑警寧澤晾剖,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站梯嗽,受9級特大地震影響齿尽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜灯节,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一循头、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧炎疆,春花似錦卡骂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唯笙,卻和暖如春螟蒸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背崩掘。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工七嫌, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苞慢。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓诵原,卻偏偏與公主長得像,于是被迫代替她去往敵國和親挽放。 傳聞我的和親對象是個殘疾皇子绍赛,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 親 情 當(dāng)眼淚順著臉頰靜靜地流淌時,我體會到了遇見真實的自己竟是如此美好辑畦! 今晚聽女兒訴說...
    復(fù)活的鳥閱讀 697評論 0 0
  • ——記冬令營之社會實踐“一元城市生活挑戰(zhàn)賽” 法國教育學(xué)家盧梭提出“回歸自然”的教育觀纯出◎歉荆“一元城市生活挑戰(zhàn)...
    晚熟的醉月閱讀 601評論 2 0
  • 天氣隨著時間,忽冷忽暖陨收,那一天饭豹,大雨滂沱,我以為你在哭泣务漩,那一天拄衰,大風(fēng)刮過,我以為你在傾訴饵骨。 如果我能有幸成為那一...
    扎如閱讀 352評論 2 2
  • 4月22號肾砂,一個很偶然的機(jī)會去參加了在成都舉辦的數(shù)據(jù)驅(qū)動增長大會,當(dāng)時是本著反正周末沒事就報名參加了大會的志愿者宏悦,...
    Jelly妮閱讀 835評論 1 2