标签:
在java中的java.lang.ref包中定义了三个引用类,分别是软引用、弱引用、和虚引用。这3个类提供了一种便捷的机制让我们可以和垃圾回收机制交互,同时也为缓存提供了一种机制,那么这三个类导致有什么作用呢?
SoftReference:
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
WeakReference:
弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
PhatomReference:
虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
所以从这些定义上可以看出,Reference提供了一种机制,当强引用消失之后,弱引用是否可以取到保存到head中对象,这其中需要考虑的因素就是系统gc机制。
下面通过几个例子来了解这些Reference的使用机制。
1.强引用存在
ReferenceQueue<Person> queue = new ReferenceQueue<Person>(); Person softPerson = new Person(); softPerson.setId(1); softPerson.setAge(18); softPerson.setName("zhangsan"); Person weakPerson = new Person(); weakPerson.setId(2); weakPerson.setAge(19); weakPerson.setName("lisi"); Person phantomPerson = new Person(); phantomPerson.setId(3); phantomPerson.setAge(20); phantomPerson.setName("wangwu"); SoftReference<Person> softRef = new SoftReference<Person>(softPerson); WeakReference<Person> weakRef = new WeakReference<Person>(weakPerson); PhantomReference<Person> phantomRef = new PhantomReference<Person>(phantomPerson, queue); ////////////////////softrefernece//////////////////////////////////// try { System.out.println(softRef.get().getName()); } catch (Exception e) { e.printStackTrace(); } ////////////////////weakreference/////////////////////////////////// try { System.out.println(weakRef.get().getName()); } catch (Exception e) { e.printStackTrace(); } ////////////////////phatomReference///////////////////////////////// try { System.out.println(phantomRef.get().getName()); } catch (Exception e) { e.printStackTrace(); } }
zhangsan java.lang.NullPointerException lisi at com.app.client.RefClient.main(RefClient.java:53) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
在强引用依然存在的情况下,虚引用(PhatomReference)的get()方法返回的竟然是null,为什么呢?
public class PhantomReference<T> extends Reference<T> { /** * Constructs a new phantom reference and registers it with the given * reference queue. The reference queue may be {@code null}, but this case * does not make any sense, since the reference will never be enqueued, and * the {@link #get()} method always returns {@code null}. * * @param r the referent to track * @param q the queue to register the phantom reference object with */ public PhantomReference(T r, ReferenceQueue<? super T> q) { super(r, q); } /** * Returns {@code null}. The referent of a phantom reference is not * accessible. * * @return {@code null} (always) */ @Override public T get() { return null; } }
从源码上可以看到get()方法永远都是返回null,那么这个PhatomReference类到底有什么用呢,这个我们放在最后讲解。现在只考虑SoftReference和WeakReference两个引用。
2.断开强引用
softPerson = null; weakPerson = null; ////////////////////softrefernece//////////////////////////////////// try { System.out.println(softRef.get().getName()); } catch (Exception e) { e.printStackTrace(); } ////////////////////weakreference/////////////////////////////////// try { System.out.println(weakRef.get().getName()); } catch (Exception e) { e.printStackTrace(); }
zhangsan lisi
从执行结果上看到,即使这个时候强引用断开了,但是依然可以引用到Head中的对象。在没有gc的情况下,SoftReference和WeakRefenece的作用一致。
3.系统gc之后
softPerson = null; weakPerson = null; System.gc(); ////////////////////softrefernece//////////////////////////////////// try { System.out.println(softRef.get().getName()); } catch (Exception e) { e.printStackTrace(); } ////////////////////weakreference/////////////////////////////////// try { System.out.println(weakRef.get().getName()); } catch (Exception e) { e.printStackTrace(); }
java.lang.NullPointerException zhangsan at com.app.client.RefClient.main(RefClient.java:49) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
从结果上,可以看到在垃圾回收机制运行之后,weakReference所引用的在Head中的对象被垃圾回收了,但是SoftReference在head中引用的对象依然存在。那SoftReference引用的对象在什么时候被回收呢?只要到了内存非常小的情况下才会被回收。
从上面的例子可以看出: 强引用 》 SoftReference >WeakReference .
下面再来说说PhatomRefernece类的使用,这个引用与其他两个引用最大不同就是先将引用加入到引用队列中,然后在回收Head中的对象,这样我们可以在引用队列中监视gc即将回收的对象。
public class PhatomRefClient { public static void main(String[] args) { Person p = new Person(); p.setId(1); p.setName("zhaosi"); p.setAge(17); System.out.println(p); ReferenceQueue<Person> queue = new ReferenceQueue<Person>(); PhantomReference<Person> phaRef = new PhantomReference<Person>(p, queue); p = null; System.gc(); while (true) { Object o = queue.poll(); if (o != null) { try { Field rereferent = Reference.class .getDeclaredField("referent"); rereferent.setAccessible(true); Person result = (Person)rereferent.get(o); System.out.println("system gc will kill person:" +result.getName()); System.out.println(result); } catch (Exception e) { e.printStackTrace(); } } } } }
com.app.bean.Person@5ced6f0d system gc will kill person:zhaosi com.app.bean.Person@5ced6f0d
实现简单的缓存系统
public class PersonCache { private Hashtable<Integer, PersonRef> mCache = null; private ReferenceQueue<Person> queue; private static PersonCache instance; private PersonCache() { mCache = new Hashtable<Integer, PersonRef>(); queue = new ReferenceQueue<Person>(); } public static PersonCache getInstance() { if (instance == null) { instance = new PersonCache(); } return instance; } public void cachePerson(Person p) { int id = p.getId(); PersonRef ref = new PersonRef(p, queue); mCache.put(id, ref); } public Person getPersonById(int id) { Person p = null; p = ((PersonRef) mCache.get(id)).get(); if (p == null) { mCache.remove(id); clearCache(); p = new Person(id); System.out.println("create a new Person"); cachePerson(p); } return p; } private void clearCache() { while (queue.poll() != null) ; } //inside a _key class PersonRef extends WeakReference<Person> { int _key; public PersonRef(Person referent, ReferenceQueue<? super Person> q) { super(referent, q); _key = referent.getId(); } } }
public class client { public static void main(String args[]){ Person p1 = new Person(); p1.setId(1); p1.setName("wahaha1"); p1.setAge(22); Person p2 = new Person(); p2.setId(2); p2.setName("wahaha2"); p2.setAge(22); Person p3 = new Person(); p3.setId(3); p3.setName("wahaha3"); p3.setAge(22); Person p4 = new Person(); p4.setId(4); p4.setName("wahaha4"); p4.setAge(22); PersonCache pc = PersonCache.getInstance(); pc.cachePerson(p1); pc.cachePerson(p2); pc.cachePerson(p3); pc.cachePerson(p4); p1 = null; p2 = null; p3 = null; p4 = null; System.out.println(pc.getPersonById(1).getName()); System.out.println(pc.getPersonById(2).getName()); System.out.println(pc.getPersonById(3).getName()); System.out.println(pc.getPersonById(4).getName()); } }
wahaha1 wahaha2 wahaha3 wahaha4
balalala~~
标签:
原文地址:http://my.oschina.net/summerpxy/blog/506014