科普文:一文搞懂jvm实战(二)Cleaner回收jvm资源

概叙

        在JDK9中新增了Cleaner类,该类的作用是用于替代finalize方法,更有效地释放资源并避免内存泄漏。

        在JEP260提案中,封装了大部分Sun包内部的API之余,还引入了一些新的API,其中就包含着Cleaner这个工具类。Cleaner承担着替换finalize方法的作用,为了解决finalize方法的性能问题、安全问题以及不可靠。

        在JDK1.2中,就已经有Cleaner这个类的内部实现了,不过是在sun包中实现的。由于是内部类不建议在生产代码中直接使用。不过sun包下的Cleaner类和lang包下的Cleanr类的功能是类似的。

        在Java中,Cleanerjava.lang.ref.Cleaner类的一个实例,它用于在垃圾收集器确定对象不再可达时执行清理动作。通常,这在处理本地资源(如文件句柄或数据库连接)时非常有用,确保资源在对象不再使用时能够得到释放。

        使用Cleaner的典型场景是结合使用java.lang.ref.PhantomReferencejava.lang.ref.ReferenceQueue。你可以创建一个PhantomReference到你想要跟踪的对象,并在创建时指定一个ReferenceQueue和一个Cleaner。当PhantomReference被入队时,Cleaner会执行一个清理方法,你可以在这个方法中释放资源。

Cleaner类

注意:在JDK1.9以上版本可使用

        在Java程序中提供有GC的垃圾回收机制,如果发现堆内存不足时一定要进行垃圾回收以释放内存空间,但如果某些对象在回收前需要做一些处理,可以通过覆写Object类中的finalize()方法来实现这种回收前的处理。

  • finalize()方法的定义:

@Deprecated(since="9")
protected void finalize() throws Throwable { }

        finalize()方法实际上从JDK1.0时就开始提供,但一直到JDK1.9后才发现此方法成为了不推荐使用的方法,同时这个方法上所抛出的一个Throwabke类型的异常(Erroe和Exception),在对象回收时可能会出现各种问题,但不影响回收!

public class Member {
   public Member() {
	   System.out.println("诞生!");
   }
   @Override
	protected void finalize() throws Throwable { //可能抛错误,也可能抛异常
		System.out.println("回收!");
		throw new Exception("我真的还想在活500年");
	}
}


public class Demo {
       public static void main(String[] args) {
		Member mem=new Member();  //实例化对象
		mem=null;          //垃圾,不被引用
		System.gc();//手动进行gc操作
		System.out.println("太阳照常升起,一代更比一代强");
	}
}


执行结果:

诞生!
太阳照常升起,一代更比一代强
回收


回收对象前要先finalize(),降低了内存回收的效率,而且它不能保证被及时执行,或者可能造成该对象的在次复活。
jdk1.9后出现新的替代者:java.lang.ref.Cleaner类。此种清理方式会启动一个新的清理线程,并且基于AutoCloseable接口实现资源释放。

Cleaner 类的主要方法和属性

Cleaner类中,一共就三个外部方法,一个简单的工具类。

        其中,在调用create方法时,就会新建一条线程,用于监听目标对象是否已经被回收。监听的逻辑则是用到了虚引用以及引用队列,在虚引用中,要是一个对象变成不可达后,在GC前会将该对象的虚引用放入引用队列中。详细的步骤以及逻辑可以看这篇文章【Java引用规范】虚引用以及引用队列。

如何创建和使用 Cleaner 对象

  1. 使用Cleaner.create()创建Cleaner对象。
  2. 调用cleaner.register()方法,传入监听的对象以及回收后要执行的逻辑。其中,逻辑中不能带有监听对象的引用,否则对象将永远无法被回收。

Cleaner 优点和局限性


Cleaner 类相比 Finalizer 和 PhantomReference 的优势


Cleaner 类和手动调用Close方法的区别


Cleaner 类的潜在问题和限制

  1. 每注册一个Cleaner类,就会新开一条线程用于监听目标对象是否已经进入到引用队列。直到目标对象被回收后,新线程才结束。
  2. Cleaner回收时间点无法控制。
  3. 不能替换所有的资源释放,必要时还是需要显式执行Close方法。
  4. 无法控制传入的回收执行逻辑,可能导致性能问题。

应用场景

        在JDK1.2中,就已经有这个类的内部实现了,不过是在sun包中实现的。由于是内部类不建议在生产代码中直接使用。不过sun包下的Cleaner类和lang包下的Cleanr类的功能是类似的。
        Cleaner在JDK中最典型的实现就是堆外内存的回收。我们申请到一个堆外内存后,是无法手动将该堆外内存进行显示的回收的,只能等待JVM来自动回收该内存。
        其中,自动回收的操作就是使用到了Cleaner工具类,在DirectByteBuffer的构造方法中,申请到堆外内存后,就会将堆外内存地址、申请容量以及实际内存大小传入到Deallocator类中进行空间的回收。

        Deallocator类集成了Runnable接口,在run方法中就会将对应地址的堆外内存回收。

示例1:传统的对象回收

  • li不进行手动回收
class Book{
    //无参构造
    public Book(){
        System.out.println("【构造】用心编写了一本优秀的原创技术图书!");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("【析构】图书使用完毕,可以销毁!");
    }
}
public class Application {
    public static void main(String[] args) {
        Book book = new Book();//创建实例化对象
        book = null;//断开堆内存的指向,变为垃圾空间
    }
}

运行结果:

【构造】用心编写了一本优秀的原创技术图书!

  • 调用gc()进行手动回收

如果不进行手动的gc()回收,则需要等待自动回收,自动回收的时间是不可控的!!

class Book{
    //无参构造
    public Book(){
        System.out.println("【构造】用心编写了一本优秀的原创技术图书!");
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("【析构】图书使用完毕,可以销毁!");
    }
}
public class Application {
    public static void main(String[] args) {
        Book book = new Book();//创建实例化对象
        book = null;//断开堆内存的指向,变为垃圾空间
        //如果不进行手动的gc()回收,则需要等待自动回收,自动回收的时间是不可控的!!
        System.gc();//进行垃圾回收
    }
}

运行结果如下:

【构造】用心编写了一本优秀的原创技术图书!
【析构】图书使用完毕,可以销毁!

  • 手动抛出异常

finalize()方法代码修改如下:(其他代码不变)

protected void finalize() throws Throwable {
        System.out.println("【析构】图书使用完毕,可以销毁!");
        throw new Exception("这本图书还有用,不能销毁!!");//手动抛出异常
    }


运行结果如下:

【构造】用心编写了一本优秀的原创技术图书!
【析构】图书使用完毕,可以销毁!

        以上的这种程序做法是在JDK1.9以前提供的处理形式,但这样的做法一直以来都存在严重问题。

        如果在finalize()里面出现一些线程的死锁操作,那么就可能会造成垃圾回收的失败,同时也会产生严重的线程阻塞问题

        解决方法:在JDK1.9之后,启动了一个专属的回收线程----Cleaner类

示例2:cleanable.clean();//释放时进行垃圾清除

import sun.misc.Cleaner;
class Book implements Runnable{ //设计一个回收线程
    //无参构造
    public Book(){
        System.out.println("【构造】用心编写了一本优秀的原创技术图书!");
    }
    public void read(){
        System.out.println("【读书】认真学习!");
    }
    @Override
    public void run() { //真正的回收由线程来完成!!!
        System.out.println("【析构】图书使用完毕,可以销毁!");
    }
}
class BookCleaner implements AutoCloseable{ //必须实现AutoCloseable接口
    private static final Cleaner cleaner = Cleaner.create();//创建一个回收对象
    private Cleaner.Cleanable cleanable;
    public BookCleaner(Book book){
        this.cleanable = cleaner.register(this,book);//注册一个回收线程
    }

    @Override
    public void close() throws Exception {
        this.cleanable.clean();//释放时进行垃圾清除
    }
}
public class Application {
    public static void main(String[] args) {
        Book book = new Book();
        try(BookCleaner bc = new BookCleaner()){
            book.read();//可以在中间进行一些对象的处理操作
        }catch (Exception e){}
    }
}


运行结果如下:

【构造】用心编写了一本优秀的原创技术图书!
【读书】认真学习!
【析构】图书使用完毕,可以销毁!

package cn.mldn.demo;
import java.lang.ref.Cleaner;
class Member implements Runnable {
	public Member() {
		System.out.println("诞生!");
	}
	@Override
	public void run() {	// 清除线程
		System.out.println("回收!");
	}
}
class MemberCleaning implements AutoCloseable { // 实现清除的处理
	private static final Cleaner cleaner = Cleaner.create() ; // 创建一个清除处理
	private Cleaner.Cleanable cleanable ;
	public MemberCleaning(Member member) {	// 注册待清除对象
    	this.cleanable = cleaner.register(this, member) ;	// 注册使用的对象
	}
	@Override
	public void close() throws Exception {// 自动关闭并释放
		this.cleanable.clean(); // 启动清理线程
	}
}
public class JavaAPIDemo {
	public static void main(String[] args) throws Exception {
		Member mem = new Member() ;// 实例化对象
		System.gc(); 	// 手工进行GC调用
		try (MemberCleaning mc = new MemberCleaning(mem)){/ 中间可以执行一些相关的代码
		} catch (Exception e) {}
		System.out.println("太阳照常升起,地球照样转动,一代更比一代强!");// 不受影响继续执行
	}
}


执行结果

诞生!
太阳照常升起,一代更比一代强
回收



新版本要求启动一个线程单独清除回收,防止延迟处理,保证性能,但是也不能保证垃圾被及时回收。

最好的方式是用完即使用try-with-resource机制显示释放或者放入资源池重用。

图解-java对象的生命周期

        经过以上的分析基本已经清楚对象的创建以及回收处理的操作,以下是对Java中对象的生命周期流程

  1. 创建阶段:每当使用关键字new就表示要开辟新的堆内存空间,同时每一个新的对象实例化时都需要去执行类中的构造方法,构造方法的目的是为了类中成员属性的初始化
  2. 应用阶段:利用指定的对象名称可以直接进行类之中的方法的调用处理
  3. 不可见阶段:如果现实某一个方法内部有一个对象,则该方法执行完毕后该对象将不再使用
  4. 不可达阶段:某一块堆内存已经不再有任何的栈内存所指向,那么这块空间将成为垃圾空间
  5. 收集阶段:JVM会自动的进行此块垃圾空间的标记,标记之后将准备通过GC回收释放,JDK1.8及以前的版本均使用finalize()方法,JKD1.9及以后的版本推荐使用CLeaner来完成
  6. 释放阶段:JVM重新回收垃圾的堆内存空间,供后续新对象使用

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

INTERCONNECT 添加自定义器件到 Custom 文件夹下

INTERCONNECT 添加自定义器件到 Custom 文件夹下 正文方法1方法2正文 作者本人一直坚信一件事情,Lumerical 中的所有结构都可以通过运行对应的脚本文件得到。运行脚本文件获取结构可以使得结构本身具有可迁移性和重复使用性,长远来看,一定比手动创建更方便。因此,这里我们…

Unix/Linux shell实用小程序1:生字本

前言 在日常工作学习中,我们会经常遇到一些不认识的英语单词,于时我们会打开翻译网站或者翻译软件进行查询,但是大部分工具没有生词本的功能,而有生字本的软件又需要注册登陆,免不了很麻烦,而且自己的数据…

Linux系统(CentOS)安装iptables防火墙

1,先检查是否安装了iptables 检查安装文件-执行命令:rpm -qa|grep iptables 检查安装文件-执行命令:service iptables status 2,如果安装了就卸装(iptables-1.4.21-35.el7.x86_64 是上面命令查出来的版本) 执行命令&#xff1a…

---java KMP算法---

对于在一段字符串中查找一段字符串,如果用数组遍历的方法那就效率低下,所以产生了效率更高的KMP算法 KMP算法查只需要遍历一次字符串就可以找出第一次出现的目标字符串 要学的话建议区b站看视频,学着由视频学者比较容易 我这里就提供下我实…

Vue +Echarts 二维数组获取最大值和最小值以及索引

实现图例效果 获取最大值方法&#xff1a; maxSecond(array) {let max Number.MIN_SAFE_INTEGER;for (let i 0; i < array.length; i) {const secondElement parseInt(array[i][1]);if (secondElement > max) {max secondElement;}}return max;}, 获取最大值索引&…

Citrix替换:不只是功能拉齐,更是性能体验的超越

用户在选择Citrix替换方案时&#xff0c;除了关注架构和功能的全面性&#xff0c;也期待着国产桌面办公方案带来的惊喜。 深信服桌面云不仅在基础能力和功能上做到了全面对标Citrix&#xff0c;还在用户极为重视的安全、可靠性、智能监控与排障、信创生态等方面做到了全面超越…

16_更快的速度与精度:Faster R-CNN

回顾R-CNN:链接 回顾Fast R-CNN:链接 1.1 简介 Faster R-CNN是作者Ross Girshick继Fast R-CNN后的又一力作。同样使用VGG16作推理速度在GPU上达到5fps(包括候选区域的生成)&#xff0c;准确率为网络的backbone&#xff0c;也有进一步的提升。在2015年的ILSVRC以及COCO竞赛中…

开放式运动耳机推荐的品牌都有哪些?五款2024靠谱机型推荐!

​作为一位耳机领域的资深数码评测师&#xff0c;我极力推荐开放式耳机作为日常佩戴之选。这款耳机凭借其创新的非入耳设计&#xff0c;有效避免了传统入耳式耳机长时间佩戴导致的耳道不适和感染风险&#xff0c;同时提供了稳固舒适的佩戴体验&#xff0c;特别适合运动爱好者如…

Android network - NUD检测机制(Android 14)

Android network - NUD检测机制 1. 前言2. 源码分析2.1 ClientModeImpl2.2 IpClient2.3 IpReachabilityMonitor 1. 前言 在Android系统中&#xff0c;NUD&#xff08;Neighbor Unreachable Detection&#xff09;指的是网络中的邻居不可达检测机制&#xff0c;它用于检测设备是…

LVS FILTER UNUSED OPTION

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 过滤一些版图与spice网表对不上的器件。 一般后端遇不到这个问题,因为通常是需要写到网表中的decap没有写出来造成的,如下图。

ceph-volume inventory KeyError: ‘TYPE‘ 处理

是否有人跟我一样碰到这样的情况 执行ceph-volume inventory报错 还好有错误日志可以看 [2024-07-05 11:40:40,540][ceph_volume.process][INFO ] Running command: /usr/sbin/blkid -c /dev/null -p /dev/ceph-c5fd6684-3851-49ab-bd44-f6743a79e24f/osd-block-42d41cd1-82…

半导体切割研磨废水的处理技术

半导体切割研磨废水处理是一个复杂而关键的过程&#xff0c;其废水主要来源于切割、研磨等工艺环节&#xff0c;这些过程中使用的化学品、冷却水、洗涤水等会产生含有重金属、有机物、酸碱度不稳定以及高浓度硅化合物等污染物的废水。针对这些废水的特性&#xff0c;半导体行业…

2025深圳国际消费电子展览会

2025深圳国际消费电子展览会 时间&#xff1a;2025年06月25-27日 地点&#xff1a;深圳国际会展中心(新馆) 详询主办方陆先生 I38&#xff08;前三位&#xff09; I82I&#xff08;中间四位&#xff09; 9I72&#xff08;后面四位&#xff09; 展会介绍&#xff1a; 20…

SRC实战:无中生有的接口和参数

今天分享的这个漏洞怎么说呢&#xff0c;虽然也是个高危&#xff0c;但是其实挺简单的&#xff0c;一个很eazy的越权&#xff0c;但是我觉得多多少少还是有点意思吧。 0x00 这是一个移动端的应用程序&#xff0c;前面比较常规&#xff0c;模拟器 BP&#xff0c;跑了一下所有…

你的机器人购物新体验——安全、高效、无忧

如果你跟我一样&#xff0c;对找到那些“恰到好处”的商品充满渴望&#xff0c;那么&#xff0c;让我来告诉你为什么BFT会成为你的下一个购物“心头好”。 BFT的优势 高效安全的支付体系&#xff1a;BFT交易系统保障了交易的安全性和透明性&#xff0c;让你的每一笔消费都安全…

python解析Linux top 系统信息并生成动态图表(pandas和matplotlib)

文章目录 0. 引言1. 功能2.使用步骤3. 程序架构流程图结构图 4. 数据解析模块5. 图表绘制模块6. 主程序入口7. 总结8. 附录完整代码 0. 引言 在性能调优和系统监控中&#xff0c;top 命令是一种重要工具&#xff0c;提供了实时的系统状态信息&#xff0c;如 CPU 使用率、内存使…

我爱服务器——LVM实战学习

后来呀&#xff0c;天亮之前毕业后踏入服务器领域了。。。。。。 LVM&#xff08;Logical Volume Manager&#xff09;是一个高级的磁盘管理框架&#xff0c;它允许用户将多个物理硬盘组合成一个逻辑卷&#xff0c;从而提供更大的存储空间、更高的灵活性和更好的数据管理能力。…

创业新选择:乐财业,让财税事业更简!

在市场需求和国家政策的双重驱动之下&#xff0c;【乐财业智慧财税赋能平台】基于鹦鹉智能财税系统、完善的税务资源供应链&#xff0c;财税专家团等&#xff0c;首创为企业提供“业财税”一体化的一站式财税解决方案&#xff0c;让财税生意更好做。 乐财业通过全国布局线下渠道…

Windows中Git的使用(2024最新版)

Windows中Git的使用 获取ssh keys本地绑定邮箱初始化本地仓库添加到本地缓存区提交到本地缓存区切换本地分支为main关联远程分支推送到GitHub查看推送日志 Git 2020年发布了新的默认分支名称"main"&#xff0c;取代了"master"作为主分支的名称。操作有了些…

MySQL数据库主从复制+mycat读写分离+MHA实操

目录 一、主从复制 1.1 主从复制简介 1.2 MySQL支持的复制类型 1.3 主从复制的工作过程 1.4 主从复制的同步模式 1.4.1 异步复制&#xff08;Asynchronous replication&#xff09; 1.4.2 全同步复制&#xff08;Fully synchronous replication&#xff09; 1.4.3 半同…