Reference详解
1. 概述
图片引用自https://blog.csdn.net/u011801189/article/details/52723868
根据Reference这个类里面的注释,整个Reference的继承体系跟GC是紧密联系在一起的。当Reference对象被GC处理过,说明这个Reference所指向的对象已经被回收过了,那么这个Reference对象也应该做相应的处理;如果该Reference对象注册了ReferenceQueue,那么它就会被丢到相应的ReferenceQueue中做回收处理。
从上图注意到,当Reference对象在Reference.pending队列中时,它们是用discovered
这个成员变量来完成队列的连接的;
这个Reference对象是active的状态,说明这个Reference所指向的对象还没有成为垃圾,还没有被GC过。这个Reference对象还没有进入Reference的世界,它还在GC的监控下呢;当被垃圾回收后,也就是进入Reference的世界后,这个discovered
域被复用作链表的连接,此时并不适用next指针,只是把next指向this。
当Reference对象真正被放入它所注册的ReferenceQueue里时,next指针才被使用,用来连接队列;此时discovered
域被置为null。
2. Reference适用场景
l . 软引用,一般使用于一些内存敏感性应用,做cache使用。被软引用的对象,在JVM抛出OutOfMemoryError之前,将会被回收掉。它的这个特性使得它做为进程内部的cache最为合适。
l 弱引用,一般用于保存一些跟对象生命周期相同的一些信息,一旦这些对象被垃圾回收,我们就可以对这些对象进行回收。这个是怎么做到的呢?基本上还是由于Reference所提供的功能有关。去看Reference的构造函数你会发现,它会要求传入一个ReferenceQueue,而这个Queue就是为了提供一种机制,这种机制允许程序员在对象被垃圾回收之前被通知到,而做出一些业务逻辑。而这种机制则弥补了JVM的finalizer机制的不足。因为JVM的finalizer机制并不保证finalizer一定会被调用到,这样当我们希望一个对象生命周期结束后它的相关资源也被释放的逻辑就不能够被保证。而且据说(为证实),finalizer是通过JNI实现,通过JVM调用开销也比较大。而JVM通过提供这种Reference机制,从而为程序员提供了处理资源回收的另外一种方法。
l 虚引用,也是可以提供这种对象被垃圾回收时的通知机制。只不过跟上面两个的区别是,PhantomReference的get方法被实现了一直返回null。这就意味着,当你通过ReferenceQueue拿到PhantomReference的通知时,你是不能再对它做出一个强引用的,你只能更具需要做出自己的cleanup的逻辑。这也说明了PhantomReference是pre-mortem的,也就是说实在真正finalize之前的。如果通过get方法可以获得对象本身,而后又对其建立一个强引用,则在后面的垃圾回收处理时,就会出错。所以干脆这里不让程序员获得对象的引用。而SoftReference和WeakReference应该就是在JVM的finalize机制之后的。
今天吃饭的时候想到一个问题,就是对于PhantomReference
,它的get
方法是返回的null的,如果是这样,我通过ReferenceQueue
的方式即使能拿到这个PhantomReference
,也还是不能对这个对象做实质的资源回收啊。那到底要怎么做才能回收与它的referent
想关联的资源呢?
publicclassLargeObjectFinalizerextendsPhantomReference<Object> {
publicLargeObjectFinalizer(
Object referent, ReferenceQueue<? super Object> q) {
super(referent, q);
}
publicvoidfinalizeResources() {
// free resources
System.out.println("clearing ...");
}
}
然后,在利用这个LargeObjectFinalizer
关联到我们的referent
ReferenceQueue<Object>referenceQueue = new ReferenceQueue<>();
List<LargeObjectFinalizer>references = new ArrayList<>();
List<Object>largeObjects = new ArrayList<>();
for (int i = 0; i < 10; ++i) {
Object largeObject = new Object();
largeObjects.add(largeObject);
references.add(new LargeObjectFinalizer(largeObject,referenceQueue));
}
largeObjects= null;
System.gc();
Reference<?>referenceFromQueue;
for(PhantomReference<Object> reference : references) {
System.out.println(reference.isEnqueued());
}
while((referenceFromQueue = referenceQueue.poll()) != null) {
((LargeObjectFinalizer)referenceFromQueue).finalizeResources();
referenceFromQueue.clear();
}
上面的这个例子很简单,但是足够可以说明问题,当垃圾回收工作时,会把我们的LargeObjectFinalizer
放到我们提供的referenceQueue
上,然后,我们从它上面取下我们的LargeObjectFinalizer
,调用资源回收方法finalizeResources
。
我觉得这个算是使用PhantomReference
做垃圾回收的一个典型例子了。我们并不是直接使用PhantomReference
,而是通过扩展它,将我们要关注的对象,比如这里的Object
,以及跟该对象相关联的一些资源,关联到我们的LargeObjectFinalizer
中,当然这是需要修改它的构造函数,或者通过其它的一些方式关联到这个LargeObjectFinalizer
里面的。只有这样,我们才能通过这个ReferenceQueue
的机制,达到垃圾回收的目的。
3. StrongReference、SoftReference,WeakReference、PhantomReference
强引用 > 软引用 > 弱引用 > 虚引用
⑴强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
⑵软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
⑶弱引用(WeakReference)
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
⑷虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。
由于引用和内存回收关系紧密。下面,先通过实例对内存回收有个认识;然后,进一步通过引用实例加深对引用的了解。
Reference详解相关推荐
- java reference详解_Java Reference详解
Reference是java中的引用类,它用来给普通对像进行包装,从而在JVM在GC时,按照引用类型的不同,在回收时采用不同的逻辑.先来看下这个类的继承体系: image.png 在进行对这些子类进行 ...
- ReferenceQueue、Reference详解
转载自:http://www.jianshu.com/p/f86d3a43eec5 http://www.cnblogs.com/jabnih/p/6580665.html ...
- java reference详解_你不可不知的Java引用类型之——Reference源码解析
定义 Reference是所有引用类型的父类,定义了引用的公共行为和操作. reference指代引用对象本身,referent指代reference引用的对象,下文介绍会以reference,ref ...
- docker常用命令详解
docker常用命令详解 本文只记录docker命令在大部分情境下的使用,如果想了解每一个选项的细节,请参考官方文档,这里只作为自己以后的备忘记录下来. 根据自己的理解,总的来说分为以下几种: Doc ...
- 【CV】Pytorch一小时入门教程-代码详解
目录 一.关键部分代码分解 1.定义网络 2.损失函数(代价函数) 3.更新权值 二.训练完整的分类器 1.数据处理 2. 训练模型(代码详解) CPU训练 GPU训练 CPU版本与GPU版本代码区别 ...
- 详解OpenCV中的Lucas Kanade稀疏光流单应追踪器
详解OpenCV中的Lucas Kanade稀疏光流单应追踪器 1. 效果图 2. 源码 参考 这篇博客将详细介绍OpenCV中的Lucas Kanade稀疏光流单应追踪器. 光流是由物体或相机的运动 ...
- Rocksdb 写流程,读流程,WAL文件,MANIFEST文件,ColumnFamily,Memtable,SST文件原理详解
文章目录 前言 Rocksdb写流程图 WAL 原理分析 概述 文件格式 查看WAL的工具 创建WAL 清理WAL MANIFEST原理分析 概述 查看MANIFEST的工具 创建 及 清除 MANI ...
- C++智能指针:weak_ptr实现详解
文章目录 weak_ptr描述 声明 作用 原理实现 函数成员使用 总结 weak_ptr描述 声明 头文件:<memory> 模版类:template <class T> c ...
- ORB-SLAM2代码/流程详解
ORB-SLAM2代码详解 文章目录 ORB-SLAM2代码详解 1. ORB-SLAM2代码详解01_ORB-SLAM2代码运行流程 1 运行官方Demo 1.2. 阅读代码之前你应该知道的事情 1 ...
最新文章
- mongodb cond 模糊查询_为了实现在线库的复杂查询,你还在双写吗?
- [笔试题目] 美团2015年9月后端开发工程师笔试题
- jQuery笔记[1]——jqGrid中实现自定义链接弹出subgrid
- Js黑客帝国效果 文字下落 制作过程和思路
- LeetCode 321. 拼接最大数(单调栈)*
- 服务器安装三节点RabbitMQ集群(4)
- php 修改input内容,JS简单获取并修改input文本框内容的方法示例
- rgb颜色查询工具_Web前端页面重构之工具篇(Photoshop)
- 2.3 指数加权平均
- 图神经网络(一)--综述
- Python植物大战僵尸源代码及素材
- Vue - 图片放大镜(vue-piczoom)
- linux dos2unix
- 帆软 大屏BI模板(含报表滚动,图表联动等)下载
- 2020赚钱机会总结,拾元富另附10个副业赚钱必备的工具与平台,看看你到底错过了多少钱!
- 你的链上资产存储安全吗?交易自由吗?
- GB/T35590-2017移动电源CMA检测报告,移动电源新国标检测
- 印媒称印度厂商Lava有意购买诺基亚钦奈工厂
- 4294967295,
- Figma 中文社区找到了!
热门文章
- 常见的行业认证和资质清单介绍
- python 使用正则表达式爬取淘宝店铺图片
- 默的各种写法图片_默字的意思、默的繁体字、默的笔顺笔画、默字部首和繁体字默的意思...
- 最后的舞,请与我一起跳
- Visual Studio 2017 version 15.9 官方最新版本下载(含那个啥码)
- 瑞昱网卡linux通用驱动下载,Realtek网卡驱动Win10-Realtek瑞昱通用网卡驱动Win10版下载 v10.003.0728.2015官方版--pc6下载站...
- plink提取特定染色体中特定区域内SNP位点信息
- 柱状图中xy轴怎么出现_『怎样设置excel图标的x、y轴』excel图表xy轴名称
- 如何实现文字逐个出现的打字机效果
- 详解抖音壁纸号的具体玩法,变现方法容易吗?