JAVA的引用類型

強引用:=

軟引用:SoftReference

弱引用:WeakReference

虛引用:PhantomReference

對象的可及性:

強可及對象:永遠都不會被GC回收,除非OOM

軟可及對象:當系統內存不足的時候,被GC回收

弱可及對象:當系統GC發現這個對象,就被回收

虛可及對象:虛引用用來檢測對象是否被回收

引用隊列(ReferenceQueue):

弱引用,軟引用,虛引用中都存在兩種構造器,第二種可以傳一個引用隊列,如果我們使用第二種構造參數創建引用對象時,這個引用對象就會被監聽,一旦有對象被回收,所指向它的引用對象就會被添加到引用隊列中,開發者可以把這個引用從隊列中彈出,來判斷對象是否被回收。

代碼展示:

這裏以String對象爲例:

創建一個String對象,分別用強引用,弱引用,軟引用指向這個對象

String string2=new String("abc");

//創建一個軟引用,讓它指向string2對象
SoftReference<String> sfr=new SoftReference<String>(string2);

//創建一個弱引用,讓它指向string2對象
WeakReference<String> wrf=new WeakReference<String>(string2);

注意這裏不能寫成:String str="abc",因爲"abc"是放在常量區中的,而gc是從堆內存中找垃圾對象。所以“abc”不會被回收

首先,我們刪除強引用,主動gc,並打印軟引用和弱引用的值:

string2=null;	//去掉強引用
System.gc();
System.out.println("軟引用所引用對象的值:"+sfr.get());
System.out.println("弱引用所引用對象的值:"+wrf.get());

打印結果:

軟引用所引用對象的值:abc
弱引用所引用對象的值:abc

我們發現刪除強引用後,開啓gc回收,gc並不會回收被軟引用指向的對象。

然後,我們把軟引用清空,再次主動gc,並打印弱引用的值

sfr.clear();
System.gc();
System.out.println(wrf.get());//對於弱可及對象,當系統GC發現這個對象,就被回收

打印結果:

null

我們發現當對象只剩下弱引用時,只要gc開始回收,這個對象就會被當成垃圾對象回收。

最後,我在這裏寫一下引用隊列監聽對象回收的測試:

private static void ReferenceQueueTest() {
	final ReferenceQueue<String> QUEUE=new ReferenceQueue<>();
	String str=new String("abc");
	//虛引用用來檢測對象是否被回收
	PhantomReference<String> prf=new PhantomReference<String>(str,QUEUE);
	WeakReference<String> wrf=new WeakReference<String>(str,QUEUE);
	new Thread(new Runnable() {
		@Override
		public void run() {
			while(true){
				Reference<? extends String> poll = QUEUE.poll();
				if(poll!=null){	//對象被回收
					System.out.println("--- 引用對象被回收 ---- " + poll);
                                        System.out.println("--- 回收對象 ---- " + poll.get());
				}
			}
		}
	}).start();

	try {
		Thread.sleep(2000);	//這裏模擬對象的生存時間,兩秒後強引用被刪除,對象被回收
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	str=null;	 //刪除強引用
	System.gc();	//主動gc
}

打印結果:

--- 引用對象被回收 ---- java.lang.ref.WeakReference@513065ba
--- 回收對象 ---- null
--- 引用對象被回收 ---- java.lang.ref.PhantomReference@5ff781ec
--- 回收對象 ---- null

我這裏用了一個子線程來等待引用對象進入引用隊列,我們將String對象的強引用刪除,然後主動gc,這樣子String對象就會被回收。回收後,上面測試中的弱引用對象和虛引用對象就都被放入了引用隊列中。我們將引用對象彈出隊列,就可以檢查String對象是否被回收了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章