Java中的強(qiáng)引用、軟引用、弱引用和虛引用

強(qiáng)引用

特點(diǎn):我們平常典型編碼Object obj = new Object()中的obj就是強(qiáng)引用。通過(guò)關(guān)鍵字new創(chuàng)建的對(duì)象所關(guān)聯(lián)的引用就是強(qiáng)引用。 當(dāng)JVM內(nèi)存空間不足,JVM寧愿拋出OutOfMemoryError運(yùn)行時(shí)錯(cuò)誤(OOM),使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的“存活”對(duì)象來(lái)解決內(nèi)存不足的問(wèn)題。對(duì)于一個(gè)普通的對(duì)象,如果沒(méi)有其他的引用關(guān)系,只要超過(guò)了引用的作用域或者顯式地將相應(yīng)(強(qiáng))引用賦值為 null,就是可以被垃圾收集的了,具體回收時(shí)機(jī)還是要看垃圾收集策略。

軟引用

特點(diǎn):軟引用通過(guò)SoftReference類實(shí)現(xiàn)。 軟引用的生命周期比強(qiáng)引用短一些。只有當(dāng) JVM 認(rèn)為內(nèi)存不足時(shí),才會(huì)去試圖回收軟引用指向的對(duì)象:即JVM 會(huì)確保在拋出 OutOfMemoryError 之前,清理軟引用指向的對(duì)象。軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收器回收,Java虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。后續(xù),我們可以調(diào)用ReferenceQueue的poll()方法來(lái)檢查是否有它所關(guān)心的對(duì)象被回收。如果隊(duì)列為空,將返回一個(gè)null,否則該方法返回隊(duì)列中前面的一個(gè)Reference對(duì)象。

應(yīng)用場(chǎng)景:軟引用通常用來(lái)實(shí)現(xiàn)內(nèi)存敏感的緩存。如果還有空閑內(nèi)存,就可以暫時(shí)保留緩存,當(dāng)內(nèi)存不足時(shí)清理掉,這樣就保證了使用緩存的同時(shí),不會(huì)耗盡內(nèi)存。

/**
 * java -Xms10m -Xmx10m SoftReferenceTest 
 */
public class SoftReferenceQueueTest {
    static class HeapObject {
        byte[] bs = new byte[1024 * 1024];
    }
    public static void main(String[] args) {
        ReferenceQueue<HeapObject> queue=new ReferenceQueue<>();
        SoftReference<HeapObject> softReference = new SoftReference<>(new HeapObject(),queue);
        List<HeapObject> list = new ArrayList<>();
        while (true) {
            if (softReference.get() != null) {
                list.add(new HeapObject());
                System.out.println("list.add");
            } else {
                System.out.println("---------軟引用已被回收---------");
                break;
            }
            System.gc();
        }
        Reference<? extends  HeapObject> pollRef = queue.poll();
        while (pollRef != null) {
            System.out.println(pollRef);
            System.out.println(pollRef.get());
            pollRef = queue.poll();
        }
    }
}

輸出:

list.add
list.add
list.add
list.add
list.add
list.add
list.add
---------軟引用已被回收---------
java.lang.ref.SoftReference@7d417077
null

如果去掉list.add(new HeapObject());則軟引用一直不會(huì)被回收

弱引用

弱引用通過(guò)WeakReference類實(shí)現(xiàn)。 弱引用的生命周期比軟引用短。在垃圾回收器線程掃描它所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了具有弱引用的對(duì)象,不管當(dāng)前內(nèi)存空間足夠與否,都會(huì)回收它的內(nèi)存。由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程,因此不一定會(huì)很快回收弱引用的對(duì)象。弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收,Java虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。

應(yīng)用場(chǎng)景:弱應(yīng)用同樣可用于內(nèi)存敏感的緩存。

public class WeakReferenceTest {
    static class HeapObject {
        byte[] bs = new byte[1024 * 1024];
    }
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<HeapObject> queue=new ReferenceQueue<>();
        WeakReference<HeapObject> weakReference=new WeakReference<>(new HeapObject(), queue);
        List<HeapObject> list = new ArrayList<>();

        while (true) {
            if (weakReference.get() != null) {
                System.gc();
                System.out.println("list.add");
            } else {
                System.out.println("---------弱引用已被回收---------");
                break;
            }
        }
        Reference<? extends  HeapObject> pollRef = queue.poll();
        while (pollRef != null) {
            System.out.println(pollRef);
            System.out.println(pollRef.get());
            pollRef = queue.poll();
        }
    }
}
輸出:
list.add
---------弱引用已被回收---------
java.lang.ref.WeakReference@7440e464
null

如果是弱引用,則不需要把jvm內(nèi)存呈報(bào)也會(huì)回收弱引用。

虛引用

特點(diǎn):虛引用也叫幻象引用,通過(guò)PhantomReference類來(lái)實(shí)現(xiàn)。無(wú)法通過(guò)虛引用訪問(wèn)對(duì)象的任何屬性或函數(shù)?;孟笠脙H僅是提供了一種確保對(duì)象被 finalize 以后,做某些事情的機(jī)制。如果一個(gè)對(duì)象僅持有虛引用,那么它就和沒(méi)有任何引用一樣,在任何時(shí)候都可能被垃圾回收器回收。虛引用必須和引用隊(duì)列 (ReferenceQueue)聯(lián)合使用。當(dāng)垃圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用,就會(huì)在回收對(duì)象的內(nèi)存之前,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。
ReferenceQueue queue = new ReferenceQueue ();
PhantomReference pr = new PhantomReference (object, queue);
程序可以通過(guò)判斷引用隊(duì)列中是否已經(jīng)加入了虛引用,來(lái)了解被引用的對(duì)象是否將要被垃圾回收。如果程序發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取一些程序行動(dòng)。

應(yīng)用場(chǎng)景:可用來(lái)跟蹤對(duì)象被垃圾回收器回收的活動(dòng),當(dāng)一個(gè)虛引用關(guān)聯(lián)的對(duì)象被垃圾收集器回收之前會(huì)收到一條系統(tǒng)通知。

public class PhantomReferenceTest {
    static class TestObject {

    }
    public static void main(String[] args) throws InterruptedException {
        ReferenceQueue<TestObject> queue = new ReferenceQueue<>();
        PhantomReference<TestObject> phantomReference = new PhantomReference<>(new TestObject(), queue);
        System.out.println(phantomReference.get() == null);//true
        Reference reference = queue.poll();
        System.out.println(reference);
        while (reference==null){
            reference = queue.poll();
            System.gc();
            System.out.println(reference);
        }
        System.out.println("last poll:"+queue.poll());
    }
}
輸出:
true
null
null
java.lang.ref.PhantomReference@7440e464
last poll:null

參考:https://time.geekbang.org/column/article/6970
示例參考:https://blog.csdn.net/u011179993/article/details/54564380

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容