前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >八、java对象和方法区的垃圾回收

八、java对象和方法区的垃圾回收

作者头像
栋先生
发布于 2018-09-29 08:36:54
发布于 2018-09-29 08:36:54
58800
代码可运行
举报
文章被收录于专栏:Java成长之路Java成长之路
运行总次数:0
代码可运行

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况都视为“没有必要执行”。 如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程去执行它。这里所谓的“执行”是指虚拟机会触发这个方法,但并不承诺会等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中执行缓慢,或者发生了死循环(更极端的情况),将很可能会导致F-Queue队列中其他对象永久处于等待,甚至导致整个内存回收系统崩溃。finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模的标记,如果对象要在finalize()中成功拯救自己——只要重新与引用链上的任何一个对象建立关联即可,譬如把自己(this关键字)赋值给某个类变量或者对象的成员变量,那在第二次标记时它将被移除出“即将回收”的集合;如果对象这时候还没有逃脱,那基本上它就真的被回收了。从代码清单3-2中我们可以看到一个对象的finalize()被执行,但是它仍然可以存活。

Created with Raphaël 2.1.0不可达的对象第一次标记是否有必要执行finalize()第二次标记是否拯救成功移除"即将回收"集合回收垃圾yesnoyesno

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
 * 此代码演示了两点:
 * 1.对象可以在被GC时自我拯救。
 * 2.这种自救的机会只有一次,因为一个对象的finalize()方法最多只会被系统自动调用一次
 * @author zzm
 */
public class FinalizeEscapeGC {

    public static FinalizeEscapeGC SAVE_HOOK = null;

    public void isAlive() {
        System.out.println("yes, i am still alive :)");
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize mehtod executed!");
        FinalizeEscapeGC.SAVE_HOOK = this;
    }

    public static void main(String[] args) throws Throwable {
        SAVE_HOOK = new FinalizeEscapeGC();

        //对象第一次成功拯救自己
        SAVE_HOOK = null;
        System.gc();
        // 因为Finalizer方法优先级很低,暂停0.5秒,以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }

        // 下面这段代码与上面的完全相同,但是这次自救却失败了
        SAVE_HOOK = null;
        System.gc();
        // 因为Finalizer方法优先级很低,暂停0.5秒,以等待它
        Thread.sleep(500);
        if (SAVE_HOOK != null) {
            SAVE_HOOK.isAlive();
        } else {
            System.out.println("no, i am dead :(");
        }
    }
}

从代码清单3-2的运行结果可以看出,SAVE_HOOK对象的finalize()方法确实被GC收集器触发过,并且在被收集前成功逃脱了。

另外一个值得注意的地方是,代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败,这是因为任何一个对象的finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法不会被再次执行,因此第二段代码的自救行动失败了。 finalize方法是JAVA刚诞生的时候对C/C++的一种妥协。所以,忘掉他吧。虽然他能给对象一个最后拯救自己的机会。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017年04月16日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法
什么是引用计数算法:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器值减1,引用数量为0的时候,则说明对象没有被任何引用指向,可以认定是”垃圾”对象
黎明大大
2020/09/08
2.6K1
jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法
JVM垃圾收集之——怎样判定一个对象是不是垃圾
学过了JVM的内存模型,了解了JVM将其管理的内存抽象为不同作用的内存工作区域,这个区域是连续,然后分为五个部分,各司其职。 链接: JVM内存模型——运行时数据区的特点和作用
向着百万年薪努力的小赵
2022/12/02
3440
JVM垃圾收集之——怎样判定一个对象是不是垃圾
Java 对象的自我救赎
JVM 通过可达性分析算法判断一个对象是否可以被回收 ,但并不是一个对象不可达时,就宣告“死刑”的,此时只是暂时处于”缓刑“阶段。要宣告一个对象“死刑”,至少还要经历两次标记过程。
用户3596197
2019/01/28
3930
JVM可达性分析是怎么GC的?
可达性分析是用来判断对象是否存活,通过"GC Roots"作为起点,从这个节点往下搜索,如果有有引用,则这个对象是存活的,如果没有则判定可回收的对象。
逍遥壮士
2021/07/29
8840
Java魔法堂:finalize函数
一、finalize与GC                               在GC第一次进行可达性分析时会将不可达而且该对象所属类重写finalize方法和finalize方法重未被执行过的对象追加到F-Queue当中,然后JVM会自动开启一个低优先级的守护线程Finalizer执行F-Queue中元素的finalize方法。此时可通过finalize方法重新将不可达对象与引用链关联起来,那么在GC第二次进行可达性分析时,则可逃离被回收的名单。 class FinalizeEscapeGC{
^_^肥仔John
2018/01/18
4950
Java虚拟机之垃圾收集器(5)
(1)Java 内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。
Java后端技术
2018/08/09
2780
Java虚拟机之垃圾收集器(5)
Java中一次对象的自我拯救探究
《深入理解java虚拟机》第二版 67页,一次对象自我拯救这个例子很不错,在这里分享出来。
明明如月学长
2021/08/27
4250
《深入理解Java虚拟机》读书笔记(四)
在Java的内存运行时区域的各个部分中:程序计数器、虚拟机栈、本地方法栈3个区域属于线程私有,随线程而生、随线程而灭,因此不需要过多的考虑内存的回收;所以垃圾回收的主要区域就主要集中在Java堆和方法区
DestinySkywalker
2023/01/02
3330
《深入理解Java虚拟机》读书笔记(四)
Java垃圾回收(GC)机制详解
  如果不进行垃圾回收,内存迟早都会被消耗空,因为我们在不断的分配内存空间而不进行回收。除非内存无限大,我们可以任性的分配而不回收,但是事实并非如此。所以,垃圾回收是必须的。
哲洛不闹
2019/03/08
1.2K0
深入理解Java虚拟机:垃圾收集
垃圾收集的目的在于清除不再使用的对象。gc通过确定对象是否被活动对象引用来确定是否收集该对象。两种常用的方法是引用计数和对象引用遍历。
全栈程序员站长
2022/08/28
2430
深入理解Java虚拟机:垃圾收集
深入理解 JVM 之——垃圾回收与内存分配策略
内存回收的时机是由垃圾回收器(Garbage Collector)来决定的,而垃圾回收器的具体策略和时机会根据不同的实现而有所差异。一般情况下,以下几种情况会触发内存回收:
浪漫主义狗
2023/09/06
7940
深入理解 JVM 之——垃圾回收与内存分配策略
垃圾收集器与内存分配策略
上面示例代码中有两段完全一样的代码片段,执行结果却是一次逃脱成功,一次失败了,这里任何一个finalize()方法都只会被系统自动调用一次,如果对象面临下一次回收,它的finalize()方法就不会再次执行。
程序员波特
2024/01/19
1890
垃圾收集器与内存分配策略
深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)
由于方法区中存放生命周期较长的类信息、常量、静态变量. 因此方法区就像堆的老年代,每次GC只有少量垃圾被清除.
JavaEdge
2019/11/03
3860
深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)
JVM-04垃圾收集Garbage Collection(上)【垃圾对象的判定】
谈起垃圾收集 (Garbage Collection ,GC),有3个问题是无法回避的
小小工匠
2021/08/17
4120
深入Java虚拟机--判断对象存活状态
程序计数器,虚拟机栈和本地方法栈 首先我们先来看下垃圾回收中不会管理到的内存区域,在Java虚拟机的运行时数据区我们可以看到,程序计数器,虚拟机栈,本地方法栈这三个地方是比较特别的。这个三个部分的特点就是线程私有的,它们随着线程的创建而诞生,也因线程的结束而灭亡。栈中的栈帧随着方法的进入和退出会有条不絮的执行着进栈和出栈。每一个栈帧中分配多少内存,基本上是在类结构确认下来的时候就已知的,因此这几个区域的内存分配和回收都具备确定性,在这几个区域内就不需要过多考虑回收的问题,因为方法结束或者线程结束,内存自然
九灵
2018/03/09
7830
深入Java虚拟机--判断对象存活状态
[JVM] 垃圾收集器与内存分配策略
 垃圾收集器与内存分配策略 最早人们思考GC需要完成的3件事情: 哪些内存需要回收 什么时候回收 如何回收 经过发展,内存动态分配和回收技术已经成熟,为什么还要了解GC和内存分配呢? 当需要排查各种内
wOw
2018/09/18
4230
[JVM] 垃圾收集器与内存分配策略
JVM:垃圾收集策略与算法
在堆里面存放着Java世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事是确定这些对象之中哪些还"存活"着,哪些已经"死去"了。
HLee
2021/02/24
3650
JVM:垃圾收集策略与算法
GC 原理详解
GC(Garbage Collecor)是JVM的内存回收器,当应用使用的内存不足时,会导致OOM(Out-Of-Memory)。
大发明家
2021/12/15
2510
深入理解JDK中的Reference原理和源码实现
这篇文章主要基于JDK11的源码和最近翻看的《深入理解Java虚拟机-2nd》一书的部分内容,对JDK11中的Reference(引用)做一些总结。值得注意的是,通过笔者对比一下JDK11和JDK8对于java.lang.ref包的相关实现,发现代码变化比较大,因此本文的源码分析可能并不适合于JDK11之外的JDK版本。
Throwable
2020/06/23
1.2K0
深入理解JVM的垃圾回收机制
上一篇博客介绍了Java运行时内存的各个区域。对于程序计数器、虚拟机栈、本地方法栈这三个部分而言,其生命周期与相关线程有关,随线程而生,随线程而灭。并且这三个区域的内存分配与回收具有确定性,因为当方法结束或者线程结束时,内存就自然跟着线程回收了。因此本篇文章所讲的有关内存分配和回收关注的是Java堆与方法区这两个区域。
全栈程序员站长
2022/08/11
3600
深入理解JVM的垃圾回收机制
相关推荐
jvm垃圾回收之引用计数算法和可达性分析算法(判断对象是否存活算法
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文