Java引用詳解
原文連結:https://blog.csdn.net/sunxianghuang/article/details/52267282
https://www.cnblogs.com/yw-ah/p/5830458.html
強引用(Strong Reference)
強引用是指在程式程式碼中普遍存在的,類似“Object obj=new Object()”這類的引用,只要強引用還存在,垃圾收集器永遠不會回收掉被引用的物件。
public class StrongReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=10000;//物件的個數,保證使得堆記憶體溢位 BiggerObject[] values=new BiggerObject[count]; for(int i=0;i<count;i++){ values[i]=new BiggerObject("Object-"+i); }for(int i=0;i<10;i++){ System.out.println(values[i].name); } } }
輸出:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid668.hprof ... Heap dump file created [13980085 bytes in 0.181 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at StrongReferenceTest$BiggerObject.<init>(StrongReferenceTest.java:8) at StrongReferenceTest.main(StrongReferenceTest.java:15)
因為垃圾收集器無法回收強引用關聯著的物件,從而導致堆記憶體溢位。
軟引用(Soft Reference)
用來描述一些還有用並非必要的物件。對於軟引用關聯著的物件,在系統將要發生記憶體溢位異常之前,將會把這些物件列入回收範圍進行第二次回收。如果這次回收還沒有足夠的記憶體,才會丟擲記憶體溢位異常。JDK 1.2之後,提供了SoftReference類來實現軟引用。
import java.lang.ref.SoftReference; public class SoftReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100000;//物件數量為100000,保證使得堆記憶體溢位 SoftReference[] values=new SoftReference[count]; for(int i=0;i<count;i++){ values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
輸出:
Object-99999 Exception in thread "main" java.lang.NullPointerException at SoftReferenceTest.main(SoftReferenceTest.java:21)
第一行輸出說明,使用軟引用後,原本由於堆記憶體溢位而無法正常執行的程式碼段“正常的”執行成功;
但是,當我們訪問早期建立的那些物件時,卻報java.lang.NullPointerException異常,說明早期建立的物件已經被垃圾收集器回收了。
import java.lang.ref.SoftReference; public class SoftReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//物件數量改為100,保證堆記憶體不會溢位 SoftReference[] values=new SoftReference[count]; for(int i=0;i<count;i++){ values[i]=new SoftReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.gc();//強制進行垃圾回收 System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
輸出:
Object-99 Object-0 Object-1 Object-2 Object-3 Object-4 Object-5 Object-6 Object-7 Object-8 Object-9
當堆記憶體足夠時,即使我們強制進行垃圾回收,軟引用關聯著的物件也不會被回收。
弱引用(WeakReference)
弱引用也是用來描述非必要物件的,但是他的強度比軟引用更弱一些,被軟引用關聯的物件只能生存到下一次垃圾收集發生之前。當垃圾收集器工作時,無論當前記憶體是否足夠,都會回收掉只被弱引用關聯的物件。JDK 1.2之後,提供了WeakReference類來實現弱引用。
public class WeakReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=10000;//物件數量為10000,保證使得堆記憶體溢位 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
輸出:
Object-9999 Exception in thread "main" java.lang.NullPointerException at WeakReferenceTest.main(WeakReferenceTest.java:22)
輸出結果,與軟引用相同。
public class WeakReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//物件數量改為100,保證堆記憶體不會溢位 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
輸出:
Object-99 Object-0 Object-1 Object-2 Object-3 Object-4 Object-5 Object-6 Object-7 Object-8 Object-9
當堆記憶體夠用時,正常輸出。
public class WeakReferenceTest { private static class BiggerObject{//佔用空間的一個大物件 public int[] values; public String name; public BiggerObject(String name){ this.name=name; values=new int[1024]; } } public static void main(String[] args) { int count=100;//物件數量改為100,保證堆記憶體不會溢位 WeakReference[] values=new WeakReference[count]; for(int i=0;i<count;i++){ values[i]=new WeakReference<BiggerObject>(new BiggerObject("Object-"+i)); } System.out.println(((BiggerObject)(values[values.length-1].get())).name); System.gc();//強制進行垃圾回收 for(int i=0;i<10;i++){ System.out.println(((BiggerObject)(values[i].get())).name); } } }
即使堆記憶體夠用,當我們強制進行垃圾回收時,弱引用所引用的物件還是被垃圾收集器回收。
虛引用
一個物件是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來獲取一個物件的例項。為一個物件設定虛引用關聯的唯一目的就是能在這個物件被收集器回收時收到一個系統通知。
垃圾回收時回收,無法通過引用取到物件值,可以通過如下程式碼實現
Object obj = new Object(); PhantomReference<Object> pf = new PhantomReference<Object>(obj); obj=null; pf.get();//永遠返回null pf.isEnQueued();//返回是否從記憶體中已經刪除
虛引用是每次垃圾回收的時候都會被回收,通過虛引用的get方法永遠獲取到的資料為null,因此也被成為幽靈引用。
虛引用主要用於檢測物件是否已經從記憶體中刪除。