WeakReference &&reference quene &&GC
2015-11-08 21:42
477 查看
在了解WeakReference之前,先给出一段简单的代码:
输出结果:false,true[/code]
喜欢探求究竟的童鞋会问,为啥System.gc后WeakReference马上会被回收,怎么做到的呢?让我们一起来深入Reference的源码探求个究竟.内部有两点需要注意:
1)pending和 discovered成员:
先看:pending对象
这个对象,定义为private,并且全局没有任何给它赋值的地方,根据它上面的注释,我们了解到这个变量是和垃圾回收期打交道的[/code]
再看discovered,同样为private,上下文也没有任何地方使用它
transient private Reference<T> discovered; /* used by VM */
看到了它的注释也明确写着是给VM用的。
上面两个变量对应在VM中的调用,可以参考openjdk中的hotspot源码,在hotspot/src/share/vm/memory/referenceProcessor.cpp 的ReferenceProcessor::discover_reference 方法。(根据此方法的注释由了解到虚拟机在对Reference的处理有ReferenceBasedDiscovery和RefeferentBasedDiscovery两种策略)
2)ReferenceHandler 线程
这个线程在Reference类的static构造块中启动,并且被设置为高优先级和daemon状态。
此线程要做的事情,是不断的检查pending 是否为null,如果pending不为null,则将pending进行enqueue,否则线程进入wait状态。
通过这2点,我们来看整个过程:
pending是由jvm来赋值的,当Reference内部的referent对象的可达状态改变时,jvm会将Reference对象放入pending链表。
结合代码eg1中的 o = null; 这一句,它使得o对象满足垃圾回收的条件,并且在后边显式的调用了 System.gc(),垃圾收集进行的时候会标记WeakReference所referent的对象o为不可达(使得wr.get()==null),并且通过 赋值给pending ,触发ReferenceHandler线程处理pending。
ReferenceHandler线程要做的是将pending对象enqueue,但默认我们所提供的queue,也就是从构造函数传入的是null,实际是使用了ReferenceQueue.NULL,Handler线程判断queue为ReferenceQueue.NULL则不进行操作,只有非ReferenceQueue.NULL 的queue才会将Reference进行enqueue。
ReferenceQueue.NULL相当于我们提供了一个空的Queue去监听垃圾回收器给我们的反馈(什么反馈呢?是说这个quene是给我们来用的么,例如WeakHashMap中使用的那种方式),并且对这种反馈不做任何处理。(但垃圾还是回收了???不是poll时候做的事情么?)
要处理反馈,则必须要提供一个非ReferenceQueue.NULL的queue。这个quene可以看做是GC与应用程序的一个桥梁,告知应用需要对那些reference进行处理.
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
在WeakHashMap则在内部提供了一个非NULL的ReferenceQueue
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
在 WeakHashMap 添加一个元素时,会使用 此queue来做监听器。
见put方法中的下面一句:
WeakHashMap的 put, size, clear 都会间接或直接的调用到 expungeStaleEntries()方法。[/code]
顾名思义,此方法的作用就是将 queue中陈旧的Reference进行删除,因为其内部的referent都已经不可达了。所以也将这个WeakReference包装的key从map中删除。
总结:ReferenceQueue是作为 JVM GC与上层Reference对象管理之间的一个消息传递方式,它使得我们可以对所监听的对象引用可达发生变化时做一些处理,WeakHashMap正是利用此来实现的。
用图来大致表示如下:
[code]public class WeakReferenceTest { public static void main(String[] args) throws Exception { Object o = new Object(); // 默认的构造函数,会使用ReferenceQueue.NULL 作为queue WeakReference<Object> wr = new WeakReference<Object>(o); System.out.println(wr.get() == null); o = null; System.gc(); System.out.println(wr.get() == null); } }
输出结果:false,true[/code]
喜欢探求究竟的童鞋会问,为啥System.gc后WeakReference马上会被回收,怎么做到的呢?让我们一起来深入Reference的源码探求个究竟.内部有两点需要注意:
1)pending和 discovered成员:
先看:pending对象
[code]/* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. */ private static Reference pending = null;
这个对象,定义为private,并且全局没有任何给它赋值的地方,根据它上面的注释,我们了解到这个变量是和垃圾回收期打交道的[/code]
再看discovered,同样为private,上下文也没有任何地方使用它
transient private Reference<T> discovered; /* used by VM */
看到了它的注释也明确写着是给VM用的。
上面两个变量对应在VM中的调用,可以参考openjdk中的hotspot源码,在hotspot/src/share/vm/memory/referenceProcessor.cpp 的ReferenceProcessor::discover_reference 方法。(根据此方法的注释由了解到虚拟机在对Reference的处理有ReferenceBasedDiscovery和RefeferentBasedDiscovery两种策略)
2)ReferenceHandler 线程
这个线程在Reference类的static构造块中启动,并且被设置为高优先级和daemon状态。
此线程要做的事情,是不断的检查pending 是否为null,如果pending不为null,则将pending进行enqueue,否则线程进入wait状态。
通过这2点,我们来看整个过程:
pending是由jvm来赋值的,当Reference内部的referent对象的可达状态改变时,jvm会将Reference对象放入pending链表。
结合代码eg1中的 o = null; 这一句,它使得o对象满足垃圾回收的条件,并且在后边显式的调用了 System.gc(),垃圾收集进行的时候会标记WeakReference所referent的对象o为不可达(使得wr.get()==null),并且通过 赋值给pending ,触发ReferenceHandler线程处理pending。
ReferenceHandler线程要做的是将pending对象enqueue,但默认我们所提供的queue,也就是从构造函数传入的是null,实际是使用了ReferenceQueue.NULL,Handler线程判断queue为ReferenceQueue.NULL则不进行操作,只有非ReferenceQueue.NULL 的queue才会将Reference进行enqueue。
ReferenceQueue.NULL相当于我们提供了一个空的Queue去监听垃圾回收器给我们的反馈(什么反馈呢?是说这个quene是给我们来用的么,例如WeakHashMap中使用的那种方式),并且对这种反馈不做任何处理。(但垃圾还是回收了???不是poll时候做的事情么?)
要处理反馈,则必须要提供一个非ReferenceQueue.NULL的queue。这个quene可以看做是GC与应用程序的一个桥梁,告知应用需要对那些reference进行处理.
当一个 WeakReference 开始返回 null 时, 它所指向的对象已经准备被回收, 这时可以做一些合适的清理工作. 将一个 ReferenceQueue 传给一个 Reference 的构造函数, 当对象被回收时, 虚拟机会自动将这个对象插入到 ReferenceQueue 中, WeakHashMap 就是利用 ReferenceQueue 来清除 key 已经没有强引用的 entries.
在WeakHashMap则在内部提供了一个非NULL的ReferenceQueue
private final ReferenceQueue<K> queue = new ReferenceQueue<K>();
在 WeakHashMap 添加一个元素时,会使用 此queue来做监听器。
见put方法中的下面一句:
[code]tab[i] = new Entry<K,V>(k, value, queue, h, e); 这里Entry是一个内部类,继承了WeakReference class Entry<K,V> extends WeakReference<K> implements Map.Entry<K,V>
WeakHashMap的 put, size, clear 都会间接或直接的调用到 expungeStaleEntries()方法。[/code]
顾名思义,此方法的作用就是将 queue中陈旧的Reference进行删除,因为其内部的referent都已经不可达了。所以也将这个WeakReference包装的key从map中删除。
总结:ReferenceQueue是作为 JVM GC与上层Reference对象管理之间的一个消息传递方式,它使得我们可以对所监听的对象引用可达发生变化时做一些处理,WeakHashMap正是利用此来实现的。
用图来大致表示如下:
相关文章推荐
- android 导入module,报failed to find build tools 错解决方案
- Android高级之Volley框架(二):JsonRequest
- 【DP】 HDU 3229 Jinyuetuan Puzzle
- Unable to get setting value Parameter name: profileName
- 接口 ValueStack:com.opensymphony.xwork2.util
- UINavigationController 总结
- __builtin_expect 解惑
- lightoj Answering Queries 1369 (数学转换&&技巧)
- HDU 1560DNA sequence
- 使用VS2010调用QtDesigner设计的UI文件,并实现控件功能
- EasyUI - 后台管理系统 - 增加,删除,修改
- IOS UISwitch 感觉官方提供的拓展性不够好,老感觉这个东西项目中用到需要自己定制
- UITableView 滑动自动加载更多数据
- Gson 解析 json中 value为数组
- Light OJ 1369 - Answering Queries 【规律】
- 快速排序
- Adreno Profiler GPU frequency clocks per/second
- 【2015-2016 ACM-ICPC, NEERC, Southern Subregional Contest F】【贪心+ STL-优先队列】 Gourmet and Banquet 最大活动时间
- UIGestureRecognizer(进阶)
- UIFont中fontName大全