JAVA的引用類型

1、強引用java

JAVA默認的引用類型,強引用,是在咱們的開發工做當中廣泛存在的。若是一個對象具備強引用,當內存空間不足的時候,java虛擬機寧肯拋出OOM異常,也不會回收它來釋放內存。可是咱們能夠將對象顯示的賦值爲null,則gc認爲該對象不存在引用,這時就能夠回收這個對象。具體何時收集這要取決於gc的算法。若是方法的內部有一個強引用,這個引用保存在棧中,而真正的引用內容(Object)保存在堆中。當這個方法運行完成後就會退出方法棧,則引用內容的引用不存在,這個Object會被回收。算法

    private static  void storongReference(){
        Object obj=new Object();
        Object obj2=obj;
        obj=null;
        System.gc();
        System.out.println(obj2); //java.lang.Object@7ea987ac
    }

 

2、軟引用(SoftReference)緩存

軟引用是用來描述一些非必需但仍有用的對象。在內存足夠的時候,軟引用對象不會被回收,只有在內存不足時,系統則會回收軟引用對象,若是回收了軟引用對象以後仍然沒有足夠的內存,纔會拋出內存溢出異常。軟引用一般用在對內存比較敏感的程序中,例如高速緩存區,mybatis就是用到了該方式。mybatis

/**
 * @Auther: XL
 * @Date: 2019/12/24 07:50
 * @Description:  -Xms10M -Xmx10M -XX:+PrintGCDetails
 */
public class SoftReferenceTest {
    private volatile static  Map<String,SoftReference> cacheMap=new ConcurrentHashMap<>();
    public static void main(String [] args) throws Exception{
        softReferenceNotAmple();
    }
    /**
     * SoftReference內存不足就回收
     */
    private static void  softReferenceNotAmple(){
        SoftReference reference;
       for(int i=0;i<10;i++){
           reference=new SoftReference(new byte[1024*1024*2]);
           cacheMap.put("key:"+i,reference);
       }
        cacheMap.forEach((k,v)->{
            System.out.println("key:"+k+ " value:"+v.get());
        });
    }
}

3、弱引用(WeakReference)ide

不管內存是否足夠,只要 JVM 開始進行垃圾回收,那些被弱引用關聯的對象都會被回收。函數

/**
 * @Auther: XL
 * @Date: 2019/12/24 08:02
 * @Description:
 */
public class WeakReferenceTest {
    private volatile static Map<String,WeakReference> cacheMap=new ConcurrentHashMap<>();
    public static void main(String [] args){
        weakReference();
    }

    /**
     * -Xms10M -Xmx10M -XX:+PrintGCDetails
     * 5次循環5M內存足夠使用,手動觸發gc;內存被回收
     */
    private static void  weakReference(){
        WeakReference reference;
        for(int i=0;i<5;i++){
            reference=new WeakReference(new byte[1024*1024*1]);
            cacheMap.put("key:"+i,reference);
        }
        System.gc();
        cacheMap.forEach((k,v)->{
            System.out.println("key:"+k+ " value:"+v.get());
        });
    }
}

當一個 WeakReference 開始返回 null 時, 它所指向的對象已經準備被回收, 這時能夠作一些合適的清理工做.   將一個 ReferenceQueue 傳給一個 Reference 的構造函數, 當對象被回收時, 虛擬機會自動將這個對象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 來清除 key 已經沒有強引用的 entries. 

this

 

4、虛引用(PhantomReference)spa

形同虛設,虛引用不會決定對象的生命週期,若是一個對象僅持有虛引用,那麼他和沒有任何引用同樣,在任什麼時候候均可能被垃圾收集器回收,他不能單獨使用也不能經過他訪問對象,虛引用必須和引用隊列(ReferenceQueue)聯合使用。3d

虛引用的做用:做用在於跟蹤垃圾回收過程,在對象被收集器回收時收到一個系統通知。 當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在垃圾回收後,將這個虛引用加入引用隊列,在其關聯的虛引用出隊前,不會完全銷燬該對象。 因此能夠經過檢查引用隊列中是否有相應的虛引用來判斷對象是否已經被回收了。使用虛引用的目的就是爲了得知對象被GC的時機,因此能夠利用虛引用來進行銷燬前的一些操做,好比說資源釋放等。這個虛引用對於對象而言徹底是無感知的,有沒有徹底同樣,可是對於虛引用的使用者而言,就像是待觀察的對象的把脈線,能夠經過它來觀察對象是否已經被回收,從而進行相應的處理。虛引用有一個很重要的用途就是用來作堆外內存的釋放,DirectByteBuffer就是經過虛引用來實現堆外內存的釋放的。code

/**
 * @Auther: XL
 * @Date: 2019/12/24 08:38
 * @Description:
 */
public class PhantomReferenceTest {
    public static void main(String [] args) throws Exception{
        ReferenceQueue<TestObj> queue = new ReferenceQueue<>();
        TestObj instanceA = new TestObj(); //建立對象
        PhantomReference<TestObj> phantomRef = new PhantomReference<TestObj>(instanceA, queue); //建立phantom引用
        System.out.println("gc前PhantomReference的引用:"+phantomRef.get());
        System.out.println("gc前ReferenceQueue:"+queue.poll());
        instanceA = null; // 再也不使用對象
        System.gc();
        System.out.println("第一次gc後PhantomReference的引用:"+phantomRef.get());
        System.out.println("第一次gc後ReferenceQueue:"+queue.poll());
        Thread.sleep(1000);
        System.gc();
        System.out.println("第二次gc後PhantomReference的引用:"+phantomRef.get());
        System.out.println("第二次gc後ReferenceQueue:"+queue.poll());
    }
}
class TestObj{
    @Override
    protected void finalize() throws Throwable {
        System.out.println("======"+this+"======");
        super.finalize();
    }
}
ReferenceQueue名義上是一個隊列,但實際內部並不是有實際的存儲結構,它的存儲是依賴於內部節點之間的關係來表達。能夠理解爲queue是一個相似於鏈表的結構,這裏的節點其實就是reference自己。能夠理解爲queue爲一個鏈表的容器,其本身僅存儲當前的head節點,然後面的節點由每一個reference節點本身經過next來保持便可。

ReferenceQueue通常用來與SoftReference、WeakReference或者PhantomReference配合使用,將須要關注的引用對象註冊到引用隊列後,即可以經過監控該隊列來判斷關注的對象是否被回收,從而執行相應的方法。

主要使用場景:

一、使用引用隊列進行數據監控,相似前面栗子的用法。

二、隊列監控的反向操做

相關文章
相關標籤/搜索