首页 > 编程语言 >【❀Java虚拟机】对象终止机制

【❀Java虚拟机】对象终止机制

时间:2023-04-25 14:14:52浏览次数:48  
标签:Java finalize 对象 虚拟机 System 回收 终止 obj 方法

什么是对象终止机制?

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

当垃圾回收器发现没有任何引用指向某个对象时,那么就会在垃圾回收中清除这个对象,在垃圾回收器回收此对象之前,会先调用这个对象的 finalize() 方法。

我们发现 finalize() 方法允许在子类中被重写,所以我们可以利用这个重写的方法,用于在对象被回收时进行资源的释放操作或者一些清理操作,比如:关闭文件、套接字和数据库连接等。

从功能上来说,finalize() 方法与 C++ 中的析构函数比较相似,但是Java采用的是基于垃圾回收器的自动内存管理机制,它们在本质上还有区别。

对象终止的注意细节

finalize() 方法在一个对象生命周期中,只会被调用一次( 即使被复活过 )。我们开发人员切记不要主动调用某个对象的 finalize() 方法,而是应该交给垃圾回收机制去调用。因为在 finalize() 方法中,我们可以导致对象重新复活,也就是不让垃圾回收器回收,这会影响垃圾回收器本身的工作。因为 finalize() 方法的执行时间是没有保障的,它完全由GC线程决定,也就是说,若不发生GC,那么 finalize() 方法将永远没有机会执行。因为一个糟糕的 finalize() 方法会严重影响GC的性能,所以也不建议自己去调用。

对象的三种生命状态

由于finalize()方法的存在,虚拟机中的对象一般会有三种可能的状态。

如果从所有的根节点都无法访问到某个对象,说明对象己经不再使用了。一般来说,此对象需要被回收。但事实上,也并非是“非死不可”的,这时候它们暂时处于“缓刑”阶段。因为一个无法触及的对象有可能在某一个条件下“复活”自己,如果这样,那么对它的回收就是不合理的。

  • 可触及的状态:从GC Roots根节点开始,可以到达这个对象
  • 可复活的状态:对象的所有引用都已经被释放,但是对象有可能在 finalize() 方法中复活
  • 不可触及的状态:对象的 finalize() 被调用后发现也没有被复活,那么就会进入不可触及状态,不可触及的对象不可能再被复活,因为 finalize() 只会被调用一次

对象的回收判定过程

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

如果对象A到GC Roots没有引用链,则进行第一次标记:

  • 如果对象A没有重写 finalize() 方法,或者 finalize() 方法已经被虚拟机调用过了,则虚拟机视为“没有必要执行”,此时对象A被判定为不可触及的状态
  • 如果对象A重写了 finalize() 方法,且还未执行过,那么对象A会被插入到F-Queue的队列中,然后由虚拟机自动创建的、低优先级的Finalizer线程触发其 finalize() 方法执行

对象A会被插入到F-Queue的队列中后, GC会对这个队列中的所有对象进行第二次标记:

  • 如果对象A在 finalize() 方法中也没有与引用链上的任何一个对象建立联系,那么在第二次标记时,对象A就会被判定为不可触及的状态
  • 如果对象A在 finalize() 方法中与引用链上的任何一个对象建立了联系,那么在第二次标记时,对象A就会被判定为可复活的状态。 但是当对象再次出现没有引用存在的情况时, finalize() 方法也不会被再次调用,直接被判定为不可触及的状态。

对象的回收过程演示

public class CanReliveObj {
    public static CanReliveObj obj;

    // 重写finalize方法(第二次标记)
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("调用当前类重写的finalize()方法");
        obj = this;
    }

    public static void main(String[] args) {
        try {
            obj = new CanReliveObj();

            obj = null;
            System.gc(); // 第一次标记
            System.out.println("第1次 gc");
            Thread.sleep(2000);
            if (obj == null)
                System.out.println("obj is dead");
            else
                System.out.println("obj is still alive");
            obj = null;
            System.gc();
            System.out.println("第2次 gc");
            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();
        }
    }
}

当把上面重写的finalize方法取消时:

当把上面重写的finalize方法加上时:

什么是GC Roots?

上面提到的GC Roots是什么,它是垃圾回收器在垃圾回收时进行判断的根搜索对象集合,那么如何利用工具查看代码中的GC Roots呢?

编写测试代码

public class GCRootsTest {
    public static void main(String[] args) {
        List<Object> numList = new ArrayList<>();
        Date birth = new Date();

        for (int i = 0; i < 100; i++) {
            numList.add(String.valueOf(i));
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("数据添加完毕...");
        new Scanner(System.in).next();
        numList = null;
        birth = null;
        System.out.println("对象已被置空...");
    }
}

获取堆内存的Dump文件

命令行方式

# 查看当前进程
jps
# 生成dump文件
jmap -dump:format=b,live,file=test1.bin 进程ID

 

参考:

 

标签:Java,finalize,对象,虚拟机,System,回收,终止,obj,方法
From: https://www.cnblogs.com/xfeiyun/p/17351522.html

相关文章

  • (二) Java开发细节
    目录Java开发注意事项和细节说明Java开发注意事项和细节说明Java源文件以.java为扩展名.源文件的基本组成部分是类(class).publicclassHello{ //编写一个main方法 publicstaticvoidmain(String[]args){ System.out.println("hello,world~");//分号表示语句结......
  • (一) 认识Java与Java安装
    目录Java运行机制Java编译运行Java开发细节JavaJDKJava运行机制java语言的特点:跨平台性编译后的java程序可以在不同的操作系统上运行,依靠的是不同平台的JVMJava核心机制-Java虚拟机(JVMjavavirtualmachine)JVM是一个虚拟的计算机,具有指令集并使用不同的存储区域,......
  • java ui 自动化
    1、依赖<dependency><groupId>org.seleniumhq.selenium</groupId><artifactId>selenium-java</artifactId><version>3.14.0</version></dependency>2、Chrome驱动下载......
  • 【HarmonyOS】自定义组件之JavaUI实现通用标题栏组件
    【关键字】标题栏、常用内置组件整合、JavaUI、自定义组件 【1、写在前面】平时我们在开发一个应用时,我们都知道一个完整的项目中会有很多个页面,而这些页面中会有许多通用的部分,比如通用标题栏、通用Dialog、通用下拉菜单等等,在Android开发中我们可以通过LayoutInflater.from......
  • java将word文件流转为pdf并下载
    1.pom<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><dependency><groupId>fr.opensagres.xdocreport</g......
  • 热迁移虚拟机报rpc超时
    问题背景:南网生产V区,热迁移虚拟机偶发性失败。问题现象:热迁移虚拟机有时候能成功,有时候直接报错。影响范围:影响热迁移功能问题排查过程:现场反馈源节点7需要做停机整改,所以需要将源节点7上的虚拟机热迁移走。现在迁移成功两台,然后再迁移就报错了。看到nova-compute报错第一时间想到......
  • 虚拟机热迁移一直处于迁移中的状态-v4-20210308_124243
    虚拟机热迁移一直处于迁移中的状态企业云平台产品中心共享知识库Exportedon03/08/2021TableofContents问题现象:对虚拟机进行热迁移操作,Dashboard和云服务自助平台上一直处于迁移中的状态问题原因:虚拟机存在频繁的数据读写操作,导致虚拟机迁移的速度追不上数据读写的速度,每次迁......
  • 在JavaScript的if判断中,关于数组Array的相关思考
    结论:在if判断中,无法直接使用Array转Boolean的方法判断数组是否为空数组letarray=[];//中间进行N步操作之后//...if(array){ console.log("数组为空数组");}if(array==[]){ console.log("数组为空数组");}if(array==0){ console.log("数组为空数组");}if(array......
  • Java的多线程编程模型5--Java中的CAS理论
    CAS,compareandswap的缩写,中文翻译成比较并交换。我们都知道,在java语言之前,并发就已经广泛存在并在服务器领域得到了大量的应用。所以硬件厂商老早就在芯片中加入了大量直至并发操作的原语,从而在硬件层面提升效率。在intel的CPU中,使用cmpxchg指令。在Java发展初期,java语言是不能......
  • JAVA设计模式学习10——组合模式
    组合模式(Composite)就是把部分和整体的关系用树形的结构来表示,从而使客户端能够把部分对象和组合起来的对象采用同样的方式来看待。树图结构一般包含一个根节点,若干个树枝和叶子节点。如下图:树结构的类图,其实就是组合模式的简略类图,最上面为抽象节点,左下方为叶子节点,右下方为树......