虛引用

虛引用在垃圾回收時候,搶救不了了。對象回收的時候直接回收,若是用ReferenceQueue,那麼在回收時候經過這個隊列,能夠人爲作些處理。軟引用弱引用先置位referentnull回收堆內存,而後把虛引用對象加入隊列,最後在隊列裏面回收虛引用對象。java

 

虛引用必需要和ReferenceQueue結合使用軟引用弱引用能夠不和ReferenceQueue結合使用。程序員

 

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

軟引用(SoftReferenve) : 內存充足的狀況下不會被回收,內存不充足的狀況下才會被回收。可以很好地規避OOM異常。函數

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

 

// 新建一個引用隊列spa

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

// 創建一個TestObject的弱引用對象

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

引用和軟引用在建立的時候均可以傳進去一個引用隊列(固然也能夠不使用引用隊列), 當弱引用和軟引用引用的對象須要進行回收的時候, 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在建立的時候分配內存/

相關文章
相關標籤/搜索