強引用是咱們接觸最多的引用,若果是強引用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對象