Java四種引用類型及垃圾回收

強引用

強引用是咱們接觸最多的引用,若果是強引用JVM寧願拋出OOM也不肯回收具備強引用的對象。

軟引用

具備軟引用的對象,內存空間充足的時候,垃圾回收器不會回收,當內存空間不充足的時候,垃圾回收器回收。

 

public class SoftReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        SoftReference<String> reference = new SoftReference<String>(string);
        string = null;
        System.out.println("gc()前弱引用所指向的對象是: "+reference.get());
        System.gc();//gc()不必定馬上執行垃圾回收
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()後弱引用所指向的對象是: "+reference.get());
    }
}
//結果(由於內存充足因此沒有被回收)
gc()前弱引用所指向的對象是: hello world
gc()後弱引用所指向的對象是: hello world

弱引用

在垃圾回收器線程掃描它所管轄的內存區域的過程當中,一旦發現了只具備弱引用的對象,無論當前內存空間足夠與否,都會回收它的內存。

 

public class WeakReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        WeakReference<String> reference = new WeakReference<String>(string);
        string = null;
        System.out.println("gc()前弱引用所指向的對象是: " + reference.get());
        System.gc();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()後弱引用所指向的對象是: " + reference.get());
    }
}
//結果
gc()前弱引用所指向的對象是: hello world
gc()後弱引用所指向的對象是: null

String string = "hello world";//常量池不能被回收
WeakReference<String> reference = new WeakReference<String>(string);
string = null;
System.out.println("gc()前弱引用所指向的對象是: " + reference.get());
System.gc();
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    e.printStackTrace();
}
System.out.println("gc()後弱引用所指向的對象是: " + reference.get());

//結果
gc()前弱引用所指向的對象是: hello world
gc()後弱引用所指向的對象是: hello world

虛引用

虛引用主要用來跟蹤對象被垃圾回收器回收的活動。虛引用與軟引用和弱引用的一個區別在於:虛引用必須和引用隊列 (ReferenceQueue)聯合使用。當垃圾回收器準備回收一個對象時,若是發現它還有虛引用,就會在回收對象的內存以前,把這個虛引用加入到與之關聯的引用隊列中。

 

public class PhantomReferenceTest {
    public static void main(String[] args) {
        String string = new String("hello world");
        //必須和引用隊列一塊兒使用
        PhantomReference<String> reference = new PhantomReference<String>(string,new ReferenceQueue<String>());
        string = null;
        System.out.println("gc()前虛引用所指向的對象是: " + reference.get());
        System.gc();//gc()不必定馬上執行垃圾回收
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("gc()後虛引用所指向的對象是: " + reference.get());
    }
}
//結果
gc()前虛引用所指向的對象是: null
gc()後虛引用所指向的對象是: null

一個永遠返回 null的reference 要來何用,請注意構造PhantomReference時的第二個參數 ReferenceQueue(事實上WeakReference & SoftReference 也能夠有這個參數),PhantomReference惟一的用處就是跟蹤referent什麼時候被 enqueue到ReferenceQueue中。

引用隊列

軟引用、弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊列中。

 

//軟引用和引用隊列
public class ReferenceQueueTest {
    public static void main(String[] args) throws InterruptedException {
        Object referent = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        SoftReference<Object> weakReference = new SoftReference<Object>(referent, referenceQueue);

        System.out.println("垃圾回收器或程序是否添加該引用到引用隊列:   " + weakReference.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        System.out.println("返回隊列可用的對象: " + polled);
        referent = null;
        System.gc();
        Thread.sleep(1000);
        //weakReference.enqueue();//取消註釋則運行結果和弱引用同樣
        System.out.println("垃圾回收器及程序是否添加該引用到引用隊列:   " + weakReference.isEnqueued());

        Reference<? extends Object> removed = referenceQueue.remove();
        System.out.println("阻塞移除隊列的中的引用對象:   " + removed);
    }
}
//結果(阻塞)
垃圾回收器或程序是否添加該引用到引用隊列:   false
返回隊列可用的對象: null
垃圾回收器及程序是否添加該引用到引用隊列:   false

//弱引用和引用隊列
public class WeakReferenceTest {
    public static void main(String[] args) throws InterruptedException {
        Object referent = new Object();
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<Object>();
        WeakReference<Object> weakReference = new WeakReference<Object>(referent, referenceQueue);

        System.out.println("垃圾回收器或程序是否添加該引用到引用隊列    :   " + weakReference.isEnqueued());
        Reference<? extends Object> polled = referenceQueue.poll();
        System.out.println("返回隊列可用的對象   : " + polled);
        referent = null;
        System.gc();
        Thread.sleep(1000);
        System.out.println("垃圾回收器及程序是否添加該引用到引用隊列    :   " + weakReference.isEnqueued());

        Reference<? extends Object> removed = referenceQueue.remove();
        System.out.println("阻塞移除隊列的中的引用對象   :   " + removed);
    }
}
//結果
垃圾回收器或程序是否添加該引用到引用隊列    :   false
返回隊列可用的對象   : null
垃圾回收器及程序是否添加該引用到引用隊列    :   true
阻塞移除隊列的中的引用對象   :   java.lang.ref.WeakReference@511d50c0

再談虛引用

(1)用來實現比較精細的內存使用控制java

private byte[] data = new byte[0];
private ReferenceQueue<byte[]> queue = new ReferenceQueue<byte[]>();
private PhantomReference<byte[]> ref = new PhantomReference<byte[]>(data, queue);
public byte[] get(int size) {
    if (size <= 0) {
        throw new IllegalArgumentException("Wrong buffer size");
    }
    if (data.length < size) {
        data = null;
        System.gc(); //強制運行垃圾回收器
        try {
            queue.remove(); //該方法會阻塞直到隊列非空
            ref.clear(); //幽靈引用不會自動清空,要手動運行
            ref = null;
            data = new byte[size];
            ref = new PhantomReference<byte[]>(data, queue);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    return data;
}

再談弱引用

WeakHashMap 使用 WeakReference 做爲 key, 一旦沒有指向 key 的強引用, WeakHashMap 在 GC 後將自動刪除相關的 entry。(ThreadLocal中有WeakHashMap的使用,你們能夠看看ThreadLocal的源碼緩存

Map<Object, Object> weakHashMap = new WeakHashMap<Object, Object>();
Object key = new Object();
Object value = new Object();
weakHashMap.put(key, value);
System.out.println(weakHashMap.containsValue(value));

key = null;
System.gc();
Thread.sleep(1000);


//一旦沒有指向 key 的強引用, WeakHashMap 在 GC 後將自動刪除相關的 entry

System.out.println(weakHashMap.containsValue(value));

//結果
true
false

再談軟引用

一個對象具備軟引用,當內存充足的時候垃圾回收器不會回收該對象,當內存不足的時候對象會被回收。這個特色因此軟引用用來實現內存敏感的高速緩存。使用軟引用能防止內存泄露,加強程序的健壯性。 spa

參考:線程

http://www.iteye.com/topic/401478code

http://www.infoq.com/cn/articles/cf-java-garbage-references對象

相關文章
相關標籤/搜索