【JAVA】【源码学习】Cleaner/Reference

简介

上一篇讲DirectByteBuffer时提到Cleaner用于释放内存,而Cleaner又跟Reference有关,那本篇就学习一下相关知识。

Cleaner

类注释很清楚的说明了,这个是一种轻量级的finalize机制(相对于VM调用而言),不管是内存还是其它资源都可以通过该机制释放。其机制主要是基于PhantomReference,这个一会讲到,先看下Clean而的源码:

public class Cleanerextends PhantomReference<Object>
{// Dummy reference queue, needed because the PhantomReference constructor// insists that we pass a queue.  Nothing will ever be placed on this queue// since the reference handler invokes cleaners explicitly.// 用于PhantomReferenceprivate static final ReferenceQueue<Object> dummyQueue = new ReferenceQueue<>();// Doubly-linked list of live cleaners, which prevents the cleaners// themselves from being GC'd before their referents// 这一点比较关键,上面注释说的很清楚,防止cleaner对象本身比要清理的对象提前被GCstatic private Cleaner first = null;// 双向链表private Cleanernext = null,prev = null;// 链表ADD操作,线程保护private static synchronized Cleaner add(Cleaner cl) // 链表REMOVE操作,线程保护private static synchronized boolean remove(Cleaner cl)private final Runnable thunk;private Cleaner(Object referent, Runnable thunk) // ob: 需要清理的对象// thunk: 负责资源清理的代码public static Cleaner create(Object ob, Runnable thunk) {if (thunk == null)return null;return add(new Cleaner(ob, thunk));}/*** 执行清理代码,会被父类调用*/public void clean() {if (!remove(this))return;try {thunk.run();} catch (final Throwable x) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {if (System.err != null)new Error("Cleaner terminated abnormally", x).printStackTrace();System.exit(1);return null;}});}}
}

整个代码比较简单,除了需要使用双向链表存储cleaner对象外,其它的就是封装。

PhantomReference

源码很简单,其中get函数直接返回null,也就是使用该类型的引用时,不管对象有没有被回收,都返回null。所以正常情况下应该用不着,典型场景就是Cleaner了。

public class PhantomReference<T> extends Reference<T> {// 直接返回nullpublic T get() {return null;}public PhantomReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}
}

Reference

重头戏来了,Reference是WeakReference、SoftReference以及PhantomReference的基类,也是VM会操作的对象(所以reference才知道对象什么时候被回收啊),管理整个进程的reference对象,整个源码也很简洁,挑几个重点看下。

1 状态

类注释中讲了划分为几种状态,开始不理解,看完源码后,觉得应该是区分Reference的几种场景的,也就是区分类中几个变量在不同场景下的意义的,本身并没有一个类似状态变量的东西来确定当前Reference的状态。

  • Active:存活。垃圾回收器检测到对象可以被回收之后,如果有ReferenceQueue,则变为Pending状态,否则到Inactive状态。
  • Pending: 等待入队列 .
  • Queued:进入队列中
  • Inactive:去活,到这个状态后,状态不会再变更。

这样讲比较抽象,结合代码看,先看下相关变量的注释:

	/* When active:   NULL*     pending:   this*    Enqueued:   next reference in queue (or this if last)*    Inactive:   this*/@SuppressWarnings("rawtypes")volatile Reference next;/* When active:   next element in a discovered reference list maintained by GC (or this if last)*     pending:   next element in the pending list (or null if last)*   otherwise:   NULL*/transient private Reference<T> discovered;  /* used by VM */

next主要用于queued状态时,以便查找另外一个入队待处理的reference;而discovered则是在pending态下下一个待入队的reference对象。

2 清理线程

JAVA 的垃圾清理机制是用后台线程来回收内存,Reference的机制也是类似。

static {ThreadGroup tg = Thread.currentThread().getThreadGroup();for (ThreadGroup tgn = tg;tgn != null;tg = tgn, tgn = tg.getParent());Thread handler = new ReferenceHandler(tg, "Reference Handler");/* If there were a special system-only priority greater than* MAX_PRIORITY, it would be used here*/handler.setPriority(Thread.MAX_PRIORITY);handler.setDaemon(true);handler.start();// provide access in SharedSecretsSharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {@Overridepublic boolean tryHandlePendingReference() {return tryHandlePending(false);}});}
private static class ReferenceHandler extends Thread {...ReferenceHandler(ThreadGroup g, String name) {super(g, name);}public void run() {while (true) {tryHandlePending(true);}}}

可见进程内会初始化一个MAX_PRIORITY的后台线程来处理,最终会调用到tryHandlePending函数。

3 清理执行

tryHandlePending是最终进行清理的地方(Cleaner里的clean),以及队列维护.

static boolean tryHandlePending(boolean waitForNotify) {Reference<Object> r;Cleaner c;try {synchronized (lock) {// 结合前面的状态来看。if (pending != null) {// pending不为null,说明被VM的回收器检测到对象被回收了(是否finalize了不一定)r = pending;// 'instanceof' might throw OutOfMemoryError sometimes// so do this before un-linking 'r' from the 'pending' chain...c = r instanceof Cleaner ? (Cleaner) r : null;// unlink 'r' from 'pending' chain// pending状态下,discovered是指下一个pending的reference对象pending = r.discovered;r.discovered = null;} else {// The waiting on the lock may cause an OutOfMemoryError// because it may try to allocate exception objects.if (waitForNotify) {lock.wait();}// retry if waitedreturn waitForNotify;}}} catch (OutOfMemoryError x) {// Give other threads CPU time so they hopefully drop some live references// and GC reclaims some space.// Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above// persistently throws OOME for some time...Thread.yield();// retryreturn true;} catch (InterruptedException x) {// retryreturn true;}// Fast path for cleanersif (c != null) {c.clean();return true;}// clean调用后,进入队列ReferenceQueue<? super Object> q = r.queue;if (q != ReferenceQueue.NULL) q.enqueue(r);return true;}

整个逻辑就是这样,VM负责通知Reference对象已经被回收了,Reference的清理线程在后台不停的工作,进行清理及列表维护。

ReferenceQueue

源码不贴了,逻辑比较简单,使用head维持一个链表。

WeakReference

看源码就是一个标记类,啥都没干,注释上有这么一句 Weak references are most often used to implement canonicalizing mappings,不太理解。

public class WeakReference<T> extends Reference<T> {public WeakReference(T referent) {super(referent);}public WeakReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}
}

SoftReference

也很简单,只不过多了clock和timestamp变量,clock由VM更新,timestamp也由VM使用。注释里有比较重要的说明

All soft references to softly-reachable objects are guaranteed to have been cleared before the virtual machine throws an OutOfMemoryError. Otherwise no constraints are placed upon the time at which a soft reference will be cleared or the order in which a set of such references to different objects will be cleared. Virtual machine implementations are, however, encouraged to bias against clearing recently-created or recently-used soft references.

这个很清楚的说明了VM保证在抛出OutOfMemoryError前会被清理,但是除此之外,何时被清理以及清理顺序是没有任何保证的。

public class SoftReference<T> extends Reference<T> {static private long clock;private long timestamp;public SoftReference(T referent) {super(referent);this.timestamp = clock;}public SoftReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);this.timestamp = clock;}public T get() {T o = super.get();if (o != null && this.timestamp != clock)this.timestamp = clock;return o;}
}

总结

看完之后,cleaner机制是理解了,但是soft和weak又有点迷惑,我只能粗浅的理解,内存紧张的时候,作用差不多,够用的时候,soft存活时间稍微长点?感觉也不一定哦,没看到注释里说优先清理weak类型的啊,懵~~~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/5455.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

20 成员变量和局部变量的区别

在一个对象类中&#xff0c;会存在成员变量和局部变量&#xff0c;他们有以下区别&#xff1a; 1.成员变量定义在方法外&#xff0c;局部变量定义在方法内&#xff1b; 2.只要new出来的对象存在&#xff0c;成员变量就存在&#xff0c;而局部变量在方法调用完之后就会消失&…

【Linux】信号保存信号处理

前言&#xff1a;对信号产生的思考 上一篇博客所说的信号产生&#xff0c;最终都要有OS来进行执行&#xff0c;为什么&#xff1f;OS是进程的管理者&#xff01;信号的处理是否是立即处理的&#xff1f;在合适的时候 -》那什么是合适的时候&#xff1f;信号如图不是被立即处理…

Windows安装RabbitMQ

Windows安装RabbitMQ 前言配置erlang环境下载配置环境变量验证 安装RabbitMQ验证 参考 前言 本文并不涉及到RabbitMQ的底层原理&#xff0c;或者别的一些特性说明&#xff0c;仅仅只是安装。 配置erlang环境 因为RabbitMQ是使用该语言开发的。 下载 下载地址&#xff1a; …

《qt quick核心编程》笔记一

1.基础HelloWorld代码 import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15Window {width: 400height: 300visible: truetitle: qsTr("Hello 1World")Rectangle {width: parent.widthheight: parent.heightcolor: "gray"Text {…

【数据挖掘】bytewax 与 ydata工具可实时了解您的数据

一、说明 在这篇博文中&#xff0c;我们将介绍如何将开源流式处理解决方案 bytewax 与 ydata 分析相结合并加以利用&#xff0c;以提高流式处理流的质量。 STream 处理支持在传输中和存储之前对数据进行实时分析&#xff0c;并且可以是有状态的&#xff0c;也可以是无状态的。 …

【网络编程】网络套接字udp通用服务器和客户端

1.预备知识 认识端口号 端口号(port)是传输层协议的内容&#xff1a; 端口号是一个2字节16位的整数(uint16)端口号用来标识主机上的一个进程IP地址port能够标识网络上的某一台主机和某一个进程一个端口号只能被一个进程占用 认识TCP协议 此处我们先对TCP(Transmission Con…

Spring MVC异步上传、跨服务器上传和文件下载

一、异步上传 之前的上传方案&#xff0c;在上传成功后都会跳转页面。而在实际开发中&#xff0c;很多情况下上传后不进行跳转&#xff0c;而是进行页面的局部刷新&#xff0c;比如&#xff1a;上传头像成功后将头像显示在网页中。这时候就需要使用异步文件上传。 1.1 JSP页面 …

JAVA泛型使用常用场景

在公共组件开发过程中&#xff0c;泛型使用常常是框架灵活性的一个重要手段。 总结了一下&#xff0c;我在开发过程中泛型使用和设计主要是这几个方面 对象容器&#xff0c;提供对象的存放和获取创建对象&#xff0c;提供对象的创建能力 对象容器 常见的比如我们的HashMap&a…

[golang gin框架] 41.Gin商城项目-微服务实战之后台Rbac微服务(用户登录 、Gorm数据库配置单独抽离、 Consul配置单独抽离)

上一节抽离了captcha验证码功能,集成了验证码微服务功能,这一节来看看后台Rbac功能,并抽离其中的用户登录,管理员管理,角色管理,权限管理等功能作为微服务来调用 一.引入 后台操作从登录到后台首页,然后其中的管理员管理,角色管理,权限管理等功能可以抽离出来作为 一个Rbac微服…

Python实战

官方文档 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 LearnPythonPython 实现功能点demo

OpenCV for Python 实战(一):获取图片拍摄GPS地址并自动添加水印

Hello 我们在OpenCV每天的基础博客当中已经更新了很多了&#xff0c;那么今天我们就来结合前几天的内容。做一个获取属性然后添加对应属性的水印。那让我们赶快开始吧~ 文章目录 图片EXIFPython 获取EXIFexifread库使用方法转换成文字地址 添加水印cv2.putText() 每日总结 图片…

【001 操作系统】什么是线程、进程?线程进程的区别是什么?

一、什么是线程、进程&#xff1f; 进程&#xff1a;进程是资源分配的基本单位&#xff0c;它是程序执行时的一个实例&#xff0c;在程序运行时创建。 在Linux环境下&#xff0c;每个进程有自己各自独立的 4G 地址空间&#xff0c;大家互不干扰对方&#xff0c;如果两个进程之间…

基于大模型的Text2SQL微调的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

笙默考试管理系统-MyExamTest(8)

笙默考试管理系统-MyExamTest&#xff08;8&#xff09; 目录 一、 笙默考试管理系统-MyExamTest 二、 笙默考试管理系统-MyExamTest 三、 笙默考试管理系统-MyExamTest 四、 笙默考试管理系统-MyExamTest 五、 笙默考试管理系统-MyExamTest 笙默考试管理系统-MyExam…

Homography单应性矩阵

1. Homography 单应性概念 考虑 同一个平面(比如书皮)的两张图片&#xff0c;红点表示同一个物理坐标点在两张图片上的各自位置。在 CV 术语中&#xff0c;我们称之为对应点。 Homography 就是将一张图像上的点映射到另一张图像上对应点的3x3变换矩阵. 因为 Homography 是一个 …

Python模块requests基本用法

简介 Python 的 requests 模块是一个流行的第三方库&#xff0c;用于发送HTTP请求。它提供了一组简洁且易于使用的API&#xff0c;使得在Python中进行网络通信变得更加简单和灵活。 目录 1. 基本概念 1.1. HTTP 协议 1.2. GET 请求 1.3. POST 请求 1.4. get 和 post 的区别…

java本地socket服务端暴露至公网访问【内网穿透】

前言 &#x1f4d5;作者简介&#xff1a;热爱跑步的恒川&#xff0c;致力于C/C、Java、Python等多编程语言&#xff0c;热爱跑步&#xff0c;喜爱音乐的一位博主。 &#x1f4d7;本文收录于恒川的日常汇报系列&#xff0c;大家有兴趣的可以看一看 &#x1f4d8;相关专栏C语言初…

蓝桥杯专题-真题版含答案-【生命之树】【消除尾一】【密码脱落】【生日蜡烛】

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…

【Java项目实战-牛客社区】--idea maven配置

第一 IDEA集成Maven插件&#xff0c;并配置Maven 以下步骤中&#xff0c;重点关注红色方框的配置 第二 IDEA 创建 Maven 项目 步骤一&#xff1a;创建模块&#xff0c;选择Maven&#xff0c;点击Next 步骤二&#xff1a;填写模块名称&#xff0c;坐标信息&#xff0c;点击finis…

【技术面试】Java八股文业余选手-下篇(持续更新)

文章目录 5. RocketMQ 消息中间件、RabbitMQ、ActiveMQ【√】5.1 RocketMQ 6. Kafka 大数据量消息中间件、ElasticSearch、ZooKeeper【√】6.1 Kafka【√】6.2 ElasticSearch 7. 分布式、研发提效、高并发、线程安全【√】7.1 分布式与集群【√】7.2 高并发、线程安全【】7.3 研…