WeakReference &&reference quene &&GC
在了解WeakReference之前,先给出一段简单的代码:
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
喜欢探求究竟的童鞋会问,为啥System.gc后WeakReference马上会被回收,怎么做到的呢?让我们一起来深入Reference的源码探求个究竟.内部有两点需要注意:
1)pending和 discovered成员:
先看:pending对象
/* 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,并且全局没有任何给它赋值的地方,根据它上面的注释,我们了解到这个变量是和垃圾回收期打交道的
再看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方法中的下面一句:
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()方法。
顾名思义,此方法的作用就是将 queue中陈旧的Reference进行删除,因为其内部的referent都已经不可达了。所以也将这个WeakReference包装的key从map中删除。
总结:ReferenceQueue是作为 JVM GC与上层Reference对象管理之间的一个消息传递方式,它使得我们可以对所监听的对象引用可达发生变化时做一些处理,WeakHashMap正是利用此来实现的。
用图来大致表示如下:

WeakReference &&reference quene &&GC的更多相关文章
- WeakReference Reference ReferenceQueue
public class WeakReference<T> extends Reference<T> { public WeakReference(T referent) { ...
- Reference Counting GC (Part one)
目录 引用计数法 计数器值的增减 new_obj()和update_ptr()函数 new_obj()生成对象 update_ptr()更新指针ptr,对计数器进行增减 优点 可即可回收垃圾 最大暂停 ...
- Reference Counting GC (Part two :Partial Mark & Sweep)
目录 部分标记清除算法 前提 dec_ref_cnt()函数 new_obj()函数 scan_hatch_queue()函数 paint_gray()函数 scan_gray()函数 collect ...
- Java Reference 源码分析
@(Java)[Reference] Java Reference 源码分析 Reference对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互.即可以使 ...
- 深入理解StrongReference,SoftReference, WeakReference和PhantomReference
Java 中一共有 4 种类型的引用 : StrongReference. SoftReference. WeakReference 以及 PhantomReference (传说中的幽灵引用 呵呵) ...
- GC真正的垃圾:强、软、弱、和虚 对象
垃圾回收的基本思想就是判断一个对象是否可触及性,说白了就是判断一个对象是否可以访问,如果对象对引用了,说明对象正在被使用,如果发现对象没有被引用,说明对象已经不再使用了,不再使用的对象可以被回收,但是 ...
- JDK源码分析(8)之 Reference 完全解读
在阅读本文之前最好对 Reference 框架有一个整体的把握,可以参考我上一篇博客 Reference 框架概览 :本文主要讲了 Reference 的子类实现和应用(SoftReference,W ...
- java Reference
相关讲解,参考: Java Reference 源码分析 Java Reference详解 Reference: // 名称说明下:Reference指代引用对象本身,Referent指代被引用对象 ...
- SoftReference、WeakReference、PhantomRefrence分析和比较
级别 什么时候被垃圾回收 用途 生存时间 强引用 从来不会 对象的一般状态 JVM停止运行时终止 软引用 在内存不足时 优化内存使用 内存不足时终止 弱引用 在垃圾回收时 对象缓存 gc运行后终止 虚 ...
随机推荐
- easyui在datagrid只想选择一条
<table class="" id="jgrid" data-options="fitColumns:true,rownumbers: tru ...
- 生成比较短的Token字符串
有的时候,我们需要生成一些Token作为标识:如认证后的标识符,资源的提取码等.一个比较常见的算法是生成一个GUID来作为Token,由于GUID的随机性和唯一性特点,作为Token是一个非常可靠的选 ...
- [六省联考2017]组合数问题 (矩阵优化$dp$)
题目链接 Solution 矩阵优化 \(dp\). 题中给出的式子的意思就是: 求 nk 个物品中选出 mod k 为 r 的个数的物品的方案数. 考虑朴素 \(dp\) ,定义状态 \(f[i][ ...
- ajax跨域两个方法
1在后端转换,调用API. ajax瀑布流: <!DOCTYPE html> <html> <head> <meta charset="UTF-8& ...
- 关于getAttribute()和setAttribute()的总结
继续声明:欲练其功,必先自宫.博主正处在自宫阶段,修炼得道者多多指教. 最近在看<JavaScript DOM 编程艺术>这本书,看到了getAttribute()和setAttribut ...
- 讲的很详细的一篇关于object equals() & hashCode() 的文章
转: 讲的很详细的一篇关于object equals() & hashCode() 的文章 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java ...
- 修车(bzoj 1070)
Description 同一时刻有N位车主带着他们的爱车来到了汽车维修中心.维修中心共有M位技术人员,不同的技术人员对不同的车进行维修所用的时间是不同的.现在需要安排这M位技术人员所维修的车及顺序,使 ...
- USACO 刷题记录bzoj
bzoj 1606: [Usaco2008 Dec]Hay For Sale 购买干草——背包 #include<cstdio> #include<cstring> #incl ...
- Linux/Unix编程中的线程安全问题【转】
转自:http://blog.csdn.net/zhengzhoudaxue2/article/details/6432984 在目前的计算机科学中,线程是操作系统调度的最小单元,进程是资源分配的最小 ...
- VIM使用技巧3
假如有如下代码: var foo = "method("+argument1+","+argument2+")" 任务:在每个“+”前后各 ...