强、软、弱、虚引用例子

简介: <div>下面用更多的例子来说明一下各种引用的用法:</div> <h2>第一个场景:后退</h2> <div><pre code_snippet_id="559981" snippet_file_name="blog_20141223_1_2511316" name="code" class="java">public class LastStep { Holder d = ne
下面用更多的例子来说明一下各种引用的用法:

第一个场景:后退

public class LastStep {
	Holder d = new Holder();
	SoftReference<Holder> sr = new SoftReference<Holder>(d);
	public static void main(String[] args) {
		
	}
	
	public Holder getHolder(){
		if(sr.get() == null){
			return new Holder();
		}else{
			return sr.get();
		}
	}
}
当在比较短的时间内想再次获取已经用过的对象的时候可以这样来做, 如果还在就直接使用,不在了才创建,可以减少new 的对象的次数

第二个场景:缓存

很多时候我们可以使用一个Map作为缓存,这样的问题在于保存在map中的对象不会被垃圾回收掉。 
借助于SoftReference对象的能够通过get()找回还没被回收对象的能力,可以把原本要缓存的对象改为缓存reference,这样,对象如果在内存足够的时候会被缓存,而不够的时候又会清空掉。
但是又会引入一个问题,SoftReference自己的对象又会无法清理,这里可以借助ReferenceQueue的能力,当Reference所持有的对象被GC后会把该Reference放到queue中的能力。通过遍历queue的方式来找到那个SoftReference已经不需要存在了来进行清理。
基于上诉内容,做一个对内存比较敏感的缓存,代码如下:
用于占位引起GC的Holder:
public class Holder {
	private static final int MB = 1024 * 1024;
	
	private byte[] holder;
	public Holder() {
		this.holder = new byte[1 * MB];
	}
}


class ObjectRef<T> extends SoftReference<T>{
	private String key;
	public ObjectRef(String key, T value, ReferenceQueue<T> q) {
		super(value);
		this.setKey(key);
	}
	public String getKey() {
		return key;
	}
	public void setKey(String key) {
		this.key = key;
	}
}


public class Cache<T> {
	private Map<String, ObjectRef<T>> cacheData;
	private ReferenceQueue<T> q;
	
	public static <T> Cache<T> getInstance(){
		return new Cache<T>();
	}
	
	private Cache() {
		cacheData = new HashMap<String, ObjectRef<T>>();
		q = new ReferenceQueue<T>();
	}
	
	public T getData(String key){
		T t = null;
		if(cacheData.containsKey(key)){
			ObjectRef<T> sr = cacheData.get(key);
			t = sr.get();
		}
		return t;
	}
	
	public void cache(String key, T t) {
		cleanCache();
		ObjectRef<T> ref = new ObjectRef<T>(key, t, q);
		cacheData.put(key, ref);
	}

	private void cleanCache() {
		ObjectRef<T> ref = null;
		while((ref = (ObjectRef<T>) q.poll()) != null){
			cacheData.remove(ref.getKey());
		}
	}

	public static void main(String[] args) throws InterruptedException {
		Cache<Holder> c = Cache.getInstance();
		{
			Holder d1 = new Holder();
			c.cache("test", d1);
			Holder holder = c.getData("test");
			System.out.println(holder);
		}
		
		Holder d2 = new Holder();
		Holder d3 = new Holder();
		Holder d4 = new Holder();
		Holder d5 = new Holder();
		Holder holder = c.getData("test");
		System.out.println(holder);
	}
}
使用JVM参数执行:
-verbose:gc -Xms2m -Xmx2m -Xmn1m -XX:SurvivorRatio=8 -XX:+PrintGCDetails
该代码将会打印:
com.price.effective.create.Holder@ca0b6
null
说明其在内存足够的时候不会被回收,不够的时候才会被回收

场景三 使用WeakHashMap 

对于上面的例子, 及一些用全局Map保存了长连接等大对象的场景, 合适回收这些对象的问题可以很好的使用WeakHashMap来解决。
WeakHashMap的key是一些WeakReference, 当Key失效时,其会清理该key,及该key对应的值。这样可以防止内存泄露。

场景四  检测对象被回收

虽然有finallize方法会在垃圾回收的时候执行,但是这样我们并不能很好的记录那些文件被回收了,使用虚引用,可以在不影响对象声明周期的情况下,监控对象的被回收的情况。如下:
public class ReferenceLeaning {
	public static void main(String[] args) {
		{
			final ReferenceQueue<Holder> q = new ReferenceQueue<Holder>();
			Holder d1 = new Holder();
			PhantomReference<Holder> r1 = new PhantomReference<Holder>(d1, q);
			
			new Thread(new Runnable() {
				@Override
				public void run() {
					while(true){
						PhantomReference<Holder> ref = (PhantomReference<Holder>) q.poll();
						if(ref != null){
							try {
								Field referent = Reference.class  
								        .getDeclaredField("referent");
								referent.setAccessible(true);  
	                            Object result = referent.get(ref);
	                            System.out.println(result);
	                            result = null;
							} catch (SecurityException e) {
								e.printStackTrace();
							} catch (NoSuchFieldException e) {
								e.printStackTrace();
							} catch (IllegalArgumentException e) {
								e.printStackTrace();
							} catch (IllegalAccessException e) {
								e.printStackTrace();
							}  
                            
						}
					}
				}
			}).start();
		}
		Holder d2 = new Holder();
		Holder d3 = new Holder();
		Holder d4 = new Holder();
	}
}

可以打印出正在准备回收的类,
因为PhantomReference的get方法永远返回null,因此用反射来得到其值, 但是例子中的这段代码又会使得对象不被回收了,因此最后又赋值为null.
其实这个例子并不好。 也没想到更有用的使用虚引用的方式,如果以后遇到了再补充。




相关文章
|
7月前
|
存储 缓存 算法
(五)JVM成神路之对象内存布局、分配过程、从生至死历程、强弱软虚引用全面剖析
在上篇文章中曾详细谈到了JVM的内存区域,其中也曾提及了:Java程序运行过程中,绝大部分创建的对象都会被分配在堆空间内。而本篇文章则会站在对象实例的角度,阐述一个Java对象从生到死的历程、Java对象在内存中的布局以及对象引用类型。
199 8
|
8月前
|
存储 Swift
Swift开发——弱占用
Swift的自动引用计数(ARC)管理类实例内存,通过强引用保持实例存活。当出现强引用循环时,可使用`weak`关键字创建弱引用,避免阻止实例释放。弱引用在不再被强引用时导致对象立即释放。示例中,添加`weak`至`author`和`book`变量防止引用循环,使得两者析构器均执行,释放内存。图2展示了弱引用结构,当解除所有强引用后,ARC自动释放实例,调用析构器。
222 1
Swift开发——弱占用
|
9月前
|
缓存 Java
Java中四种引用类型(强、软、弱、虚)
Java中四种引用类型(强、软、弱、虚)
|
9月前
|
Java
Java异常处理:解释一下异常的传播机制。
Java异常处理:解释一下异常的传播机制。
152 1
|
存储 编译器 C++
c++ 有趣的动态转换之 delete 崩溃探究兼谈基类虚析构的重要性
c++ 有趣的动态转换之 delete 崩溃探究兼谈基类虚析构的重要性
|
Java
强、软、弱、虚,你是哪一种?
强、软、弱、虚,你是哪一种?
71 0
|
缓存 安全 Java
ThreadLocal之强、弱、软、虚引用(上)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(上)
|
存储 监控 安全
ThreadLocal之强、弱、软、虚引用(下)
ThreadLocal之强、弱、软、虚引用
ThreadLocal之强、弱、软、虚引用(下)
|
Java
强、软、弱、虚引用
强、软、弱、虚引用
117 0
编程基本功:即使是脚本,也尽量减少硬代码,都使用变量
编程基本功:即使是脚本,也尽量减少硬代码,都使用变量
79 0

热门文章

最新文章