jvm诊断与优化(5)

上章说标记算法通过根标记可达对象。是否可达(可触)这与实例的引用级别也有很大的关系。下面说几种在java中的引用级别,除了强引用其他3种都可以在java.lang.ref中找到

1.强引用

  程序中默认的引用方式。正常的赋值就是如 List<String> strs = new ArrayList()<String>() ; 那么 strs就是一个强引用。被强引用的对象为可达(可触)对象,GC无法对其回收就算内存溢出也不愿意

2.软引用

    被软引用的对象在GC觉得内存不足时就会对其进行回收,无法知道对象在哪一时刻被销毁。这种引用用于缓存最好不过了。例:

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.弱引用

    比软件引用更加弱了,被弱引用的对象在GC一触发时就被销毁了。同样合适与缓存方式(但没有上面好,因为GC触发机率是比较高的,所以数据很容易被销毁)例:

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触发了一次,这时“张三”对象就被销毁了。在引用队列中可以获取了它的弱引用,但你再也找不回“张三”了。

你可能感兴趣的:(jvm诊断与优化(5))