jvm診斷與優化(5)

上章說標記算法經過根標記可達對象。是否可達(可觸)這與實例的引用級別也有很大的關係。下面說幾種在java中的引用級別,除了強引用其餘3種均可以在java.lang.ref中找到 java

1.強引用 算法

  程序中默認的引用方式。正常的賦值就是如 List<String> strs = new ArrayList()<String>() ; 那麼 strs就是一個強引用。被強引用的對象爲可達(可觸)對象,GC沒法對其回收就算內存溢出也不肯意 緩存

2.軟引用 ide

    被軟引用的對象在GC以爲內存不足時就會對其進行回收,沒法知道對象在哪一時刻被銷燬。這種引用用於緩存最好不過了。例: this

import java.lang.ref.SoftReference;

public class SoftRef {
	public static class People{
		private String name;
		private String gender;
		public People(String name, String gender) {
			this.name = name;
			this.gender = gender;
		}
		//get/set ....
	}
	
	public static void main(String[] args) {
		People zs = new People("張三", "男");//這是一個強引用
		SoftReference<People> PeopleSoftRef = 
                    new SoftReference<SoftRef.People>(zs);//建立了軟引用
		zs = null;	//消除強引用
		zs = PeopleSoftRef.get(); //軟引用方式取得對象,這個對象有可能不存在被GC回收了
	}
	
}

3.弱引用 spa

    比軟件引用更加弱了,被弱引用的對象在GC一觸發時就被銷燬了。一樣合適與緩存方式(但沒有上面好,由於GC觸發機率是比較高的,因此數據很容易被銷燬)例: code

import java.lang.ref.WeakReference;

public class WeakSoft {
	public static class People{
		//somethig...
	}
	public static void main(String[] args) {
		WeakReference<People> peopleWeak = 
                   new WeakReference<WeakSoft.People>(new People("張三", "男"));
		People zs = peopleWeak.get(); //弱引用方式取得對象,這個對象頗有可能已經被銷燬了
	}
}

4.虛引用(瞭解) 對象

    這個是引用類型中最弱的,持有虛引用的對象有跟沒有同樣。如上當你試圖用get()取出,總會失敗。是一個不可達對象,虛引用必須和引用隊列一塊兒使用。它的做用僅僅在於跟蹤回收過程(就是它被GC回收,在隊列中讓你知道一下就ok了)。 隊列

-------------------------------------------------------------------- 進程

擴展 軟引用、弱引用、虛引用與它們的引用隊列

    這三種引用隨時會被GC回收,但回收後它會被丟到引用隊列中,在隊列中你能夠找到它們的身影,但僅用來跟蹤查看而已例:

java -Xmx10M -XX:+PrintGC WeakSoft 

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;

public class WeakSoft {
	public static ReferenceQueue<People> peopleWeakQueue =
               new ReferenceQueue<People>();//引用隊列
	
	public static class People{ 
	      //somethig
	}
	
	public static class PeopleWeakRef extends WeakReference<People>{
		private String name;
		
		public PeopleWeakRef(People referent, ReferenceQueue<? super People> q) {
			super(referent, q);
			this.name = referent.getName();
		}
		//get/set
	}
	
	public static class TraceRefQueue implements Runnable{

		@Override
		public void run() {
			while (true) {
					PeopleWeakRef peopleRef = null;
					try {
						peopleRef = (PeopleWeakRef) peopleWeakQueue.remove();
					} catch (InterruptedException e) {
						throw new RuntimeException(e);
					}
					if(peopleRef!=null){
						System.out.println(peopleRef.getName()+" 被移除了!");
						System.out.println(peopleRef.get());
					}
			}
		}
		
	}
	
	public static void main(String[] args) throws InterruptedException {
		Thread traceRefQueueThread = 
                   new Thread(new TraceRefQueue());//啓動一個守護進程,監聽GC移除動做
		traceRefQueueThread.setDaemon(true);
		traceRefQueueThread.start();
		PeopleWeakRef peopleWeakRef =
                    new PeopleWeakRef(new People("張三", "男"),peopleWeakQueue);
		//讓GC觸發
		byte[] memory = new byte[3*1024*1024];
		memory = new byte[2*1024*1024];
		memory = new byte[2*1024*1024];
	}
}
最後結果:

[GC 5794K->5632K(9728K), 0.0078318 secs]
張三 被移除了!
null

輸出說明:看到GC觸發了一次,這時「張三」對象就被銷燬了。在引用隊列中能夠獲取了它的弱引用,但你再也找不回「張三」了。

相關文章
相關標籤/搜索