虛引用


虛引用在垃圾回收時候,搶救不了了。對象回收的時候直接回收,如果用ReferenceQueue,那么在回收時候通過這個隊列,可以人為做些處理。軟引用弱引用先置位referentnull回收堆內存,然后把虛引用對象加入隊列,最后在隊列里面回收虛引用對象。

 

虛引用必須要和ReferenceQueue結合使用軟引用弱引用可以不和ReferenceQueue結合使用。

 

強引用 : 就是普通的引用. 內存不足拋 Out of Memory 異常

軟引用(SoftReferenve) : 內存充足的情況下不會被回收,內存不充足的情況下才會被回收。能夠很好地規避OOM異常。

弱引用(WeakReference) : 當垃圾回收機制運行時, 弱引用引用的對象就會被回收掉.

 

// 新建一個引用隊列

ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();

// 建立一個TestObject的弱引用

SoftReference<TestObject> reference = new SoftReference<>(new TestObject(), referenceQueue)

引用和軟引用在創建的時候都可以傳進去一個引用隊列(當然也可以不使用引用隊列), 當弱引用和軟引用引用的對象需要進行回收的時候, JVM都是先將其referent字段設置成null,之后將軟引用或弱引用對象本身,加入到關聯的引用隊列中。也就是說JVM先回收堆對象內存,然后才將軟引用或弱引用本身加入到引用隊列。

 

// 創建一個引用隊列

ReferenceQueue<TestObject> referenceQueue = new ReferenceQueue<>();

PhantomReference reference = new PhantomReference<>(new TestObject(), referenceQueue);

而虛引用(PhantomReference) 不同, 必須和引用隊列 ReferenceQueue)聯合使用, GC啟動時, 則將引用對象傳到它的引用隊列中去. 但是不會將虛引用的referent字段設置成null, 就是不會釋放虛引用指向的TestObject堆對象內存空間

 

如果虛引用引用的對象重寫了finalize方法, 在虛引用對象傳到它的引用隊列之前還會調用對象的finalize方法, 但是調用之后內存不會回收.
你可以通過手動調用PhantomReference.clear()方法來釋放虛引用指向的的堆對象內存空間

 

虛引用的存在更傾向於實現程序員對內存回收的細粒度性控制, 當虛引用確定會被回收之后, 會向應用程序發送通知, 此時程序員進行對內存清理的細微操作.

 

public static void main(String[] args) {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakRef = new WeakReference<Object>(obj, refQueue);
        System.out.println(weakRef.get());//返回weakRef里面的obj
        System.out.println(refQueue.poll());//隊列滅有元素
        obj = null;//只有weakRef 指向new Object()內存,不置位null,gc時候不會將weakRef 的eferent被置位了null,也不會將weakRef加入refQueue隊列
        System.gc();
        System.gc();
        System.gc();
        System.gc();//System.gc()是告訴JVM這是一個執行GC的好時機,但具體執不執行由JVM決定,
        System.out.println(weakRef.get());//referent被置位了null
        System.out.println(refQueue.poll());//隊列里面有一個元素weakRef但是weakRef的referent被置位了null
    }

 

 public class Test0009 {
    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
        PhantomReference<Object> phanRef = new PhantomReference<Object>(obj, refQueue);
        System.out.println(phanRef.get());//null,phanRef里面有元素但是一直返回null,因為PhantomReference重寫了Reference的get方法,寫死了返回null
        System.out.println(refQueue.poll());//隊列為空,
        obj = null;//不置位null,phanRef里面有元素,隊列為空。
        System.gc();
        System.gc();
        System.gc();
        System.out.println(phanRef.get());//phanRef里面仍然有元素,referent並沒有像弱引用軟引用那樣置位空
        System.out.println(refQueue.poll());//隊列有元素,
    }
}
class Registry {
    private Set registeredObjects = new HashSet();
 
    public void register(Object object) {
        registeredObjects.add( object );
    }
}
所有我添加進 registeredObjects 中的object永遠不會被GC回收,因為這里有個強引用保存在registeredObjects里,
object 內存對象被2個強引用關聯。另一方面如果我把代碼改為如下:
class Registry {
     private Set registeredObjects = new HashSet();
 
     public void register(Object object) {
         registeredObjects.add( new WeakReference(object) );
     }
 }
現在如果GC想要回收registeredObjects中的object,object 內存對象被1個強引用1個弱引用關聯,便能夠實現了,
同樣在使用HashMap如果想實現如上的效果,一種更好的實現是使用WeakHashMap

強引用:一直不回收

軟引用:內存不足回收

弱引用:gc就回收

虛引用:  “虛引用”顧名思義,就是形同虛設,一個對象僅持有虛引用,那么它就和沒有任何引用一樣。虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用必須和引用隊列 ReferenceQueue)聯合使用。

當垃圾回收器准備回收一個對象時,如果發現它還有虛引用,就會在回收對象的內存之前,把這個虛引用加入到與之 關聯的引用隊列中。

虛引用里面的對象沒有強引用時候,開始回收,加入到隊列去,並不會置referentnull

軟引用弱引用里面的對象沒有強引用時候,開始回收,加入到隊列去,置referentnull

 

public class MyDate extends Date { 

    /** Creates a new instance of MyDate */
    public MyDate() {
    }
    // 覆蓋finalize()方法,finalize()函數是在JVM回收內存時執行的,
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("obj [Date: " + this.getTime() + "] is gc");
    }   

    public String toString() {
        return "Date: " + this.getTime();
    }
}

 

虛引用也稱為幽靈引用或者幻影引用,它是最弱的一種引用關系。一個僅僅持有虛引用的對象,和沒有引用幾乎是一樣的,隨時都有可能被垃圾回收器回收。當試圖通過虛引用的get()方法取得強引用時,總是會失敗。並且,虛引用必須和引用隊列一起使用,它的作用在於跟蹤垃圾回收過程。

當你的虛引用所引用的對象已經執行完finalize函數的時候,就會把對象加到queue里面。

廣義的堆外內

-Xmx的值是新生代和老生代的和的最大值,-XX:MaxPermSize來指定持久代的最大值Java堆的最大值其實是-Xmx和-XX:MaxPermSize的總和

那么剩下的都可以認為是堆外內存(廣義的)了,這些包括了jvm本身在運行過程中分配的內存,codecache,jni里分配的內存,DirectByteBuffer分配的內存等等

狹義的堆外內存

這個主要是指java.nio.DirectByteBuffer在創建的時候分配內存/

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM