Loading [MathJax]/jax/input/TeX/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Java 对象的自我救赎

Java 对象的自我救赎

作者头像
用户3596197
发布于 2019-04-25 06:26:31
发布于 2019-04-25 06:26:31
29200
代码可运行
举报
文章被收录于专栏:空帆船w空帆船w
运行总次数:0
代码可运行

JVM 通过可达性分析算法判断一个对象是否可以被回收 ,但并不是一个对象不可达时,就宣告“死刑”的,此时只是暂时处于”缓刑“阶段。要宣告一个对象“死刑”,至少还要经历两次标记过程。

没有必要执行 finalize() 方法的筛选条件取决于:

1、 finalize() 方法已经被执行过(finalize() 只会执行一次)。

2、对象没有重写 finalize()方法。

如果一个对象有必要执行 finalize() 方法,会进入 F-Queue 队列,等待 Finalizer 线程执行。

因此如果想要完成对象自救, finalize()是逃脱死亡的最后一次机会,重新与引用链上的任何一个对象关联起来就可以,在第二次标记时,对象会被移出回收队列,完成自救。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public static void main(String[] args) throws InterruptedException {
        SAVE_HOOK = new FinalizeEscapeGC();
        SAVE_HOOK = null;
        System.gc();
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("我挂了");
        }
    }

    public void isAlive() {
        System.out.println("我还活着");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("执行 finalize 方法");
        // 把当前对象( this )赋值给某个类变量, 重新与引用链建立引用
        SAVE_HOOK = this;
    }
}

扩展:

finalize() 方法的执行线程 Finalizer 优先级级别低,无法保证 finalize() 方法什么时候执行,执行是否符合预期,使用不当会影响性能。

Java 9 中已经将 finalize() 方法标记为废弃了,如果没有特别的原因,不要重写 finalize() 方法,也别指望它能回收资源。相反,尽量使用 try-finallytry-with-resources 等机制是非常好的资源回收方法。

参考资料

深入理解Java虚拟机:JVM高级特性与最佳实践(第2版)

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-01-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JaqenTalk 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
JVM可达性分析是怎么GC的?
可达性分析是用来判断对象是否存活,通过"GC Roots"作为起点,从这个节点往下搜索,如果有有引用,则这个对象是存活的,如果没有则判定可回收的对象。
逍遥壮士
2021/07/29
8830
JVM垃圾收集之——怎样判定一个对象是不是垃圾
学过了JVM的内存模型,了解了JVM将其管理的内存抽象为不同作用的内存工作区域,这个区域是连续,然后分为五个部分,各司其职。 链接: JVM内存模型——运行时数据区的特点和作用
向着百万年薪努力的小赵
2022/12/02
3440
JVM垃圾收集之——怎样判定一个对象是不是垃圾
Java中一次对象的自我拯救探究
《深入理解java虚拟机》第二版 67页,一次对象自我拯救这个例子很不错,在这里分享出来。
明明如月学长
2021/08/27
4240
GC 原理详解
GC(Garbage Collecor)是JVM的内存回收器,当应用使用的内存不足时,会导致OOM(Out-Of-Memory)。
大发明家
2021/12/15
2490
垃圾收集器与内存分配策略
上面示例代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败了,这里任何一个finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法就不会再次执行。
程序员波特
2024/01/19
1890
垃圾收集器与内存分配策略
一文带你读懂Object类源码
Object类是一个比较特殊的类,是所有类的超级父类,java中如果一个类没有用 extends关键字 明确指出继承于某个类,那么它默认继承Object类。下面我们一起分析这个默默被所有类所继承的 Object。
后台技术汇
2022/05/28
4370
一文带你读懂Object类源码
JVM:垃圾收集策略与算法
在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事是确定这些对象之中哪些还"存活"着,哪些已经"死去"了。
HLee
2021/02/24
3650
JVM:垃圾收集策略与算法
浅析finalize方法
由于我们通常使用的虚拟机使用的可达性分析算法,所以我们这里聊的都是可达性分析算法的相关。
田维常
2019/09/12
6570
浅析finalize方法
JVM(三)对象的生死判定和算法详解
导读:对象除了生死之外,还有其他状态吗?对象真正的死亡,难道只经历一次简单的判定?如何在垂死的边缘“拯救”一个将死对象?判断对象的生死存活都有那些算法?本文带你一起找到这些答案。
磊哥
2019/01/28
5341
JVM(三)对象的生死判定和算法详解
详细捋一捋JVM的垃圾回收机制
在日常工作或面试当中,经常会遇到JVM的垃圾回收问题,今天就来详细捋一捋相关的知识点。
田维常
2020/04/14
3910
详细捋一捋JVM的垃圾回收机制
JVM如何判断哪些对象可以回收?
我们上一篇分析的是JVM的内存分布,分为堆内存、虚拟机栈、本地方法栈、方法区以及程序计数器等主要区域;各个区域的特点我也就不啰嗦了,想看的给大家直通车:
Java宝典
2021/04/02
8070
JVM如何判断哪些对象可以回收?
八、java对象和方法区的垃圾回收
即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。 如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。从代码清单3-2中我们可以看到一个对象的finalize()被执行,但是它仍然可以存活。
栋先生
2018/09/29
5880
Java魔法堂:finalize函数
一、finalize与GC                               在GC第一次进行可达性分析时会将不可达而且该对象所属类重写finalize方法和finalize方法重未被执行过的对象追加到F-Queue当中,然后JVM会自动开启一个低优先级的守护线程Finalizer执行F-Queue中元素的finalize方法。此时可通过finalize方法重新将不可达对象与引用链关联起来,那么在GC第二次进行可达性分析时,则可逃离被回收的名单。 class FinalizeEscapeGC{
^_^肥仔John
2018/01/18
4940
深入Java虚拟机--判断对象存活状态
程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的。这个三个部分的特点就是线程私有的,它们随着线程的创建而诞生,也因线程的结束而灭亡。栈中的栈帧随着方法的进入和退出会有条不絮的执行着进栈和出栈。每一个栈帧中分配多少内存,基本上是在类结构确认下来的时候就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,因为方法结束或者线程结束,内存自然
九灵
2018/03/09
7820
深入Java虚拟机--判断对象存活状态
《深入理解Java虚拟机》读书笔记(四)
在Java的内存运行时区域的各个部分中:程序计数器、虚拟机栈、本地方法栈3个区域属于线程私有,随线程而生、随线程而灭,因此不需要过多的考虑内存的回收;所以垃圾回收的主要区域就主要集中在Java堆和方法区
DestinySkywalker
2023/01/02
3320
《深入理解Java虚拟机》读书笔记(四)
jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法
什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1,引用数量为0的时候,则说明对象没有被任何引用指向,可以认定是”垃圾”对象
黎明大大
2020/09/08
2.6K1
jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法
深入浅出JVM(十一)之如何判断对象“已死”
在方法中会创建大量的对象,对象并不一定是全局都会使用的,并且Java虚拟机的资源是有限的
菜菜的后端私房菜
2024/10/15
1020
Java虚拟机之垃圾收集器(5)
(1)Java 内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。
Java后端技术
2018/08/09
2780
Java虚拟机之垃圾收集器(5)
深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)
由于方法区中存放生命周期较长的类信息、常量、静态变量. 因此方法区就像堆的老年代,每次GC只有少量垃圾被清除.
JavaEdge
2019/11/03
3850
深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)
深入理解Java虚拟机:垃圾收集
垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。两种常用的方法是引用计数和对象引用遍历。
全栈程序员站长
2022/08/28
2430
深入理解Java虚拟机:垃圾收集
相关推荐
JVM可达性分析是怎么GC的?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验