1. 程式人生 > >Java引用詳解(強引用、軟引用、弱引用、虛引用)

Java引用詳解(強引用、軟引用、弱引用、虛引用)

強引用(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);
		} 
	} 
}
即使堆記憶體夠用,當我們強制進行垃圾回收時,弱引用所引用的物件還是被垃圾收集器回收。

虛引用

一個物件是否有虛引用的存在,完全不會對其生存時間構成影響,也無法通過虛引用來獲取一個物件的例項。為一個物件設定虛引用關聯的唯一目的就是能在這個物件被收集器回收時收到一個系統通知。

參考:

《深入理解Java虛擬機器》

http://blog.sina.com.cn/s/blog_6f6a95180100rrox.html