Java详解对象终止方法finalize()的用法

 更新时间:2022年05月10日 09:45:25   作者:羡羡ˇ  
在前面的 jvm 中, 需要补充几个部分的内容, 接着来看 finalize() 机制, 它可以使接近死亡的对象复活, 下来我们来看是怎么一回事

finalize()方法机制

Java 语言提供了对象终止(finalization)机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。

当GC去回收垃圾时, 总会在即将回收之前调用这个对象的 finalize()方法 , 一个对象finalize()方法只会被调用一次

finalize()方法可以被重写,通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件、套接字和数据库连接等。

我们一般最好不要主动去调用对象的finalize()方法, 理由有以下三点 :

1.在 finalize()时可能会导致对象复活。

2.finalize()方法的执行时间是没有保障的,它完全由 GC 线程决定,极端情况下,若不发生 GC,则 finalize()方法将没有执行机会。

3.一个糟糕的 finalize()会严重影响 GC 的性能。比如 finalize 是个死循环。

为什么会有这种机制呢 ?

我们先来了解 jvm 为对象定义的三种状态

第一次被 jvm 标为垃圾的对象此时处于"缓刑"阶段, 也就是说它此时并不是非死不可的

可触及的:从根节点开始,可以到达这个对象。

可复活的:对象的所有引用都被释放,但是对象有可能在 finalize()中复活。

不可触及的:对象的 finalize()被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为 finalize()只会被调用一次。

以上 3 种状态中,是由于 finalize()方法的存在,进行的区分。只有在对象不可触及时才可以被回收

可触及的, 意思就是说, 对象此时存在引用链, 是存活的, 可复活的意思是说, 此对象虽然已经被GC标为了垃圾, 但是此时未调用 finalize() 方法, 这个对象是有可能在finalize()中复活的. 不可触及的就是说, 此时finalize()方法已经被调用过了(没有复活), 这个对象最终的命运已经是非死不可了, 只能静等GC去回收它

那么具体的过程是怎样的呢?

判定一个对象 objA 是否可回收,至少要经历两次标记过程:

1.如果对象 objA 到 GC Roots 没有引用链,则进行第一次标记。

2.进行筛选,判断此对象是否有必要执行 finalize()方法

如果对象 objA 没有重写 finalize()方法,或者 finalize()方法已经被虚拟机调用过,则虚拟机视为“没有必要执行”,objA 被判定为不可触及的。

如果对象 objA 重写了 finalize()方法,且还未执行过,那么 objA 会被插入到 F-Queue 队列中,由一个虚拟机自动创建的、低优先级的 Finalizer 线程触发其 finalize()方法执行。finalize()方法是对象逃脱死亡的最后机会,稍后 GC 会对 F-Queue 队列中的对象进行第二次标记。如果 objA 在 finalize()方法中与引用链上的任何一个对象建立了联系,那么在第二次标记时,objA 会被移出“即将回收”集合。之后,对象会再次出现没有引用存在的情况. 在这个情况下,finalize()方法不会被再次调用,对象会直接变成不可触及的状态,也就是说,一个对象的 finalize()方法只会被调用一次。

接着我们用代码演示对象的复活

public class CanReliveObj {
	public static CanReliveObj obj;//类变量,属于 GC Root
	//此方法只能被调用一次
	 @Override
	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("调用当前类重写的finalize()方法");
		obj = this;//当前待回收的对象在finalize()方法中与引用链上的一个对象obj建立了联系
	}
	public static void main(String[] args) {
		try {
			obj = new CanReliveObj();
			// 对象第一次成功拯救自己
			obj = null;
			System.gc();//调用垃圾回收器
			System.out.println("第1次 gc");
			// 因为Finalizer线程优先级很低,暂停2秒,以等待它
			Thread.sleep(2000);
			if (obj == null) {
				System.out.println("obj is dead");
			} else {
				System.out.println("obj is still alive");
			}
			System.out.println("第2次 gc");
			// 下面这段代码与上面的完全相同,但是这次自救却失败了
			obj = null;
			System.gc();
			// 因为Finalizer线程优先级很低,暂停2秒,以等待它
			Thread.sleep(2000);
			if (obj == null) {
				System.out.println("obj is dead");
			} else {
				System.out.println("obj is still alive");
			}
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

执行结果 :

先将引用指向 null , 这时第一次GC , 我们重写了finalize()方法, 致使对象在第一次垃圾回收时成功自救, 第二次再将引用指向null , 因为finalize() 方法只会被执行一次, 这时对象只能等待死亡

到此这篇关于Java详解对象终止方法finalize()的用法的文章就介绍到这了,更多相关Java finalize()内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot中整合Ehcache实现热点数据缓存的详细过程

    SpringBoot中整合Ehcache实现热点数据缓存的详细过程

    这篇文章主要介绍了SpringBoot中整合Ehcache实现热点数据缓存,SpringBoot 中使用 Ehcache 比较简单,只需要简单配置,说白了还是 Spring Cache 的用法,合理使用缓存机制,可以很好地提高项目的响应速度,需要的朋友可以参考下
    2023-04-04
  • Java集合中的链表与结构详解

    Java集合中的链表与结构详解

    链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表实现方法及常见面试题如反转、中间节点查找等,感兴趣的朋友跟随小编一起看看吧
    2025-08-08
  • APT 注解处理器实现 Lombok 常用注解功能详解

    APT 注解处理器实现 Lombok 常用注解功能详解

    这篇文章主要为大家介绍了使用APT 注解处理器实现 Lombok 常用注解功能详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • JavaEE开发之SpringMVC中的自定义消息转换器与文件上传

    JavaEE开发之SpringMVC中的自定义消息转换器与文件上传

    本篇文章主要介绍了SpringMVC的相关知识。同时也会介绍到js、css这些静态文件的加载配置,以及服务器推送的两种实现方式并且给出了两者的区别。下面跟着小编一起来看下吧
    2017-04-04
  • IDEA2023版本创建Spring项目只能勾选17和21却无法使用Java8的完美解决方案

    IDEA2023版本创建Spring项目只能勾选17和21却无法使用Java8的完美解决方案

    想创建一个springboot的项目,本地安装的是1.8,但是在使用Spring Initializr创建项目时,发现版本只有17和21,这篇文章主要介绍了IDEA2023版本创建Sping项目只能勾选17和21,却无法使用Java8的解决方法,需要的朋友可以参考下
    2023-12-12
  • Mybatisplus如何存储List、Map

    Mybatisplus如何存储List、Map

    这篇文章主要介绍了Mybatisplus如何存储List、Map问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • 详解RocketMQ 消费端如何监听消息

    详解RocketMQ 消费端如何监听消息

    这篇文章主要为大家介绍了RocketMQ 消费端如何监听消息示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • java多线程学习之死锁的模拟和避免(实例讲解)

    java多线程学习之死锁的模拟和避免(实例讲解)

    下面小编就为大家带来一篇java多线程学习之死锁的模拟和避免(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06
  • 如何基于Springboot完成新增员工功能并设置全局异常处理器

    如何基于Springboot完成新增员工功能并设置全局异常处理器

    最近工作中遇到了做一个管理员工信息的功能,下面这篇文章主要给大家介绍了关于如何基于Springboot完成新增员工功能并设置全局异常处理器的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • Java面试题冲刺第二十六天--实战编程

    Java面试题冲刺第二十六天--实战编程

    这篇文章主要为大家分享了最有价值的三道java实战面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08

最新评论