天天看點

弱引用WeakReference和軟引用SoftReference

在Java1.2中我們可以發現一個java.lang.ref包,在這個包中我們可以發現有關引用的知識,比如WeakReference弱引用和SoftReference強引用。

弱引用(WeakReference):

隻具有弱引用的對象聲明周期更短暫,在垃圾回收期線程掃描它所管轄的記憶體區域的過程中,一旦發現了隻具有若引用的對象,不管目前記憶體空間是否足夠,都會回收它的記憶體,不過,要注意的是,由于垃圾回收期是一個優先級很低的線程,是以不一定會很快發現那些隻具有弱引用的對象。

軟引用(SoftReference):

也稱為強引用,如果一個對象隻具有軟引用,則記憶體空間足夠,垃圾回收期就不會回收它,如果記憶體空間不足了,就會回收這些對象的記憶體,如果垃圾回收期沒有回收它,該對象就可以被程式使用。

WeakReference和SoftReference的用武之地:

WeakReference通常用于在某處儲存對象的引用,而又不幹擾該對象被GC回收,如:用于Debug、記憶體監視工具等程式中。因為這類程式一般要求即要觀察到對象,又不能影響該對象正常的GC過程。

SoftReference是強引用,它儲存的對象執行個體,除非JVM即将OutOfMemory,否則不會被GC回收。這個特性使得它特别适合設計對象Cache。對于Cache,我們希望被緩存的對象最好始終常駐記憶體,但是如果JVM記憶體吃緊,為了不發生OutOfMemoryError導緻系統崩潰,必要的時候也允許JVM回收Cache的記憶體,待後續合适的時機再把資料重新Load到Cache中。這樣可以系統設計得更具彈性。

下面通過一個執行個體,來展現這兩種引用如何儲存對象執行個體的:

User.java:

public class User implements Serializable{
 
	private static final long serialVersionUID = 1L;
	
	/* 使用者id */
	private Integer uid;
	/* 使用者名 */
	private String uname;
 
	public Integer getUid() {
		return uid;
	}
 
	public void setUid(Integer uid) {
		this.uid = uid;
	}
 
	public String getUname() {
		return uname;
	}
 
	public void setUname(String uname) {
		this.uname = uname;
	}
 
}
           

WeakReferenceTest.java:

public class WeakReferenceTest {
 
	public static void main(String[] args) {
 
		/*建立User對象*/
		User user = new User();
		/*設定username*/
		user.setUname("廖澤民");
		
		/*把對象放在弱引用中*/
		WeakReference<User> weak = new WeakReference<>(user);
		
		/*把user對象置空,然後再從若引用中取值*/
		user = null;
 
		int i = 0;
 
		/*weak.get()表示從引用中取得對象*/
		while (weak.get() != null) {
 
			System.out.println(String.format("從弱引用中取值: %s, count: %d", weak.get().getUname(), ++i));
 
			if (i % 10 == 0) {
				System.gc();
				System.out.println("記憶體回收方法被調用");
			}
 
			try {
				Thread.sleep(500);
			} catch (Exception e) {
 
			}
		}
		System.out.println("對象已經被JVM回收");
 
	}
 
}
           

運作的結果:

弱引用WeakReference和軟引用SoftReference

從運作結果,我們可以發現當把對象執行個體儲存到WeakReference後,再将對象置空,然後從WeakReference中取值,當System.gc()方法被調用後,對象執行個體也會被回收!

SoftReferenceTest.java:

public class SoftReferenceTest {
 
	public static void main(String[] args) {
 
		/* 建立User對象 */
		User user = new User();
		/* 設定使用者名 */
		user.setUname("廖澤民");
 
		/* 建立強引用對象 */
		SoftReference<User> soft = new SoftReference<User>(user);
 
		/* 把user對象置空,然後再從強引用中取值【注:要先存在引用中再置空,注意順序啊】 */
		user = null;
 
		int i = 0;
 
		while (soft.get() != null) {
			System.out.println(String.format("從強引用中擷取對象: %s, count: %d", soft.get().getUname(), ++i));
			if (i % 10 == 0) {
				System.gc();
				System.out.println("記憶體回收方法被調用!");
			}
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
 
			}
		}
		System.out.println("對象已經被JVM回收!");
	}
 
}
           

運作結果:

弱引用WeakReference和軟引用SoftReference

從運作結果(程式不會停止,一直執行)可以發現,我們把對象執行個體儲存到SoftReference中,然後将對象置空,再從SoftReference中取值時,即使顯示的調用System.gc();方法,該對象執行個體也不會被回收(除非發生記憶體溢出,該對象才會被回收)