【Java 虚拟机原理】垃圾回收算法 ( 可达性分析算法 | GC Root 示例 | GC 回收前的两次标记 | finalize 方法示例 )

简介: 【Java 虚拟机原理】垃圾回收算法 ( 可达性分析算法 | GC Root 示例 | GC 回收前的两次标记 | finalize 方法示例 )

文章目录

一、可达性分析算法

二、GC Root 示例

三、GC 回收前的两次标记

四、finalize 方法示例





一、可达性分析算法


在 堆内存 中 , 存在一个 根对象 GC Root , GC Root 对象一般是如下几种情况 :


线程栈 中的 栈帧 中的 局部变量表 中的 引用对象 ;

方法区 中的 静态引用对象 ;

方法区 中的 常量引用对象 ;

本地方法栈 中的 JNI 中的 引用的对象 ;


根对象 GC Root 指向了 对象 1 ; 对象 1 又指向了 对象 2 , 对象 3 ; 对象 3 指向了 对象 4 ;


只要是 处于整个链条上的对象 , 都是 非垃圾对象 , 不能进行回收的对象 ;


不处于 引用链条 上的对象 , 就是 垃圾对象 ;

image.png


下图中 , 紫色的是存活对象 , 白色的是可回收的 垃圾对象 ;








二、GC Root 示例


找出下面程序中的 GC Root 对象 ;


public class HelloWorld {
    public static HelloWorld mHelloWorld = new HelloWorld();
    public int add() {
        int a = 1;
        int b = 1;
        int c = a + b;
        return c;
    }
    public static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld();
        helloWorld.add();
    }
}


image.png


第 13 1313 行的 helloWorld 对象是 GC Root 对象 , 符合 " 线程栈 中的 栈帧 中的 局部变量表 中的 引用对象 " 条件 ;


helloWorld 对象中有其它引用对象 , 只要引用链条没有断 , 那么链条上的对象都是 非垃圾对象 ;


一旦执行了 helloWorld = null; 语句 , 那么该对象及以下的对象就没有了引用链条 , 这个对象及之下的对象就都变成了 垃圾对象 ;






三、GC 回收前的两次标记


当对象被 定义为垃圾对象后 , 并不会马上被回收 , 只是判了个死缓 , 没有真正执行垃圾回收 ;


当 GC Root 引用链断开后 , 对象不可达 ;


JVM 会对这些 不可达对象 进行一次标记 , 然后执行一次筛选 , 执行该对象的 finalize 方法 ,


public class HelloWorld {
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
    }
}


finalize 方法是对象被 GC 垃圾回收之前 , 被调用的方法 , 该方法不能保证一定能执行完毕 , JVM 会给对象一个时间限制 , 在这个时间内执行 finalize 方法 , 重写的该方法中不要执行很耗时的操作 ;


在对象的 finalize 方法中 , 如果不想被回收 , 可以再次添加一个引用链 , 让 GC Root 对象引用自己 ;



之后 JVM 会对不可达对象 进行第二次标记 , 此时如果发现 该对象 仍然是垃圾对象 , 此时直接将该对象回收 ;


finalize 方法只会被调用一次 , JVM 对 对象第二次标记时 , 发现对象如果没有被引用 , 直接回收 , 不再调用 finalize 方法 ;






四、finalize 方法示例


创建一个对象 , 赋值给变量 A , 然后将 A 置空 , 该对象就变成了垃圾对象 ;


在 finalize 方法中 , 对象尝试自救 , 将自己赋值给 A , 这样该对象又变成了 非垃圾对象 ;


调用 System.gc() 方法后 , 一般需要暂停几秒 , 等待 finalize 方法调用 ;



这里将 A 两次置空 , 第一次调用了 finalize 方法 , 自救成功 , 没有被回收 ;


第二次置空后 , finalize 方法不再调用 , 被回收了 ;



代码示例 :


public class HelloWorld {
    public static HelloWorld A;
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        System.out.println("finalize 被调用");
        A = this;
    }
    public static void main(String[] args) throws InterruptedException {
        A = new HelloWorld();
        // 将 对象 变为垃圾对象
        A = null;
        // 进行垃圾回收
        System.gc();
        // 由于 gc 的优先级比较低
        //      等待 1000ms 看 finalize 是否被调用
        Thread.sleep(1000);
        // 本次 GC 调用之前
        //      先调用了 finalize 方法
        //      为对象添加了 GC Root 引用链
        //      该方法只会调用一次
        if (A == null) {
            System.out.println("对象被回收");
        } else {
            System.out.println("对象未被回收");
        }
        // 将 对象 变为垃圾对象
        A = null;
        // 进行垃圾回收
        System.gc();
        // 由于 gc 的优先级比较低
        //      等待 1000ms 看 finalize 是否被调用
        Thread.sleep(1000);
        // 本次调用 GC
        //      直接判断对象是否有引用链
        //      不再调用 finalize 方法
        //      发现没有引用链 , 直接回收
        if (A == null) {
            System.out.println("对象被回收");
        } else {
            System.out.println("对象未被回收");
        }
    }
}


执行结果 :


finalize 被调用
对象未被回收
对象被回收


目录
相关文章
|
监控 算法 Java
Java虚拟机(JVM)垃圾回收机制深度剖析与优化策略####
本文作为一篇技术性文章,深入探讨了Java虚拟机(JVM)中垃圾回收的工作原理,详细分析了标记-清除、复制算法、标记-压缩及分代收集等主流垃圾回收算法的特点和适用场景。通过实际案例,展示了不同GC(Garbage Collector)算法在应用中的表现差异,并针对大型应用提出了一系列优化策略,包括选择合适的GC算法、调整堆内存大小、并行与并发GC调优等,旨在帮助开发者更好地理解和优化Java应用的性能。 ####
551 27
|
监控 算法 Java
Java虚拟机(JVM)的垃圾回收机制深度解析####
本文深入探讨了Java虚拟机(JVM)的垃圾回收机制,旨在揭示其背后的工作原理与优化策略。我们将从垃圾回收的基本概念入手,逐步剖析标记-清除、复制算法、标记-整理等主流垃圾回收算法的原理与实现细节。通过对比不同算法的优缺点及适用场景,为开发者提供优化Java应用性能与内存管理的实践指南。 ####
|
机器学习/深度学习 监控 算法
Java虚拟机(JVM)的垃圾回收机制深度剖析####
本文深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法、性能调优策略及未来趋势。通过实例解析,为开发者提供优化Java应用性能的思路与方法。 ####
559 28
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
1464 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
算法 Java
JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
本文详细介绍了JVM中的GC算法,包括年轻代的复制算法和老年代的标记-整理算法。复制算法适用于年轻代,因其高效且能避免内存碎片;标记-整理算法则用于老年代,虽然效率较低,但能有效解决内存碎片问题。文章还解释了这两种算法的具体过程及其优缺点,并简要提及了其他GC算法。
 JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
|
监控 算法 Java
Java虚拟机垃圾回收机制深度剖析与优化策略####
【10月更文挑战第21天】 本文旨在深入探讨Java虚拟机(JVM)中的垃圾回收机制,揭示其工作原理、常见算法及参数调优技巧。通过案例分析,展示如何根据应用特性调整GC策略,以提升Java应用的性能和稳定性,为开发者提供实战中的优化指南。 ####
321 5
|
存储 监控 算法
Java虚拟机(JVM)垃圾回收机制深度解析与优化策略####
本文旨在深入探讨Java虚拟机(JVM)的垃圾回收机制,揭示其工作原理、常见算法及参数调优方法。通过剖析垃圾回收的生命周期、内存区域划分以及GC日志分析,为开发者提供一套实用的JVM垃圾回收优化指南,助力提升Java应用的性能与稳定性。 ####
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
587 6
|
监控 算法 Java
深入理解Java的垃圾回收机制
【10月更文挑战第22天】在Java的世界里,有一个默默无闻却至关重要的角色——垃圾回收(Garbage Collection, GC)。就像城市的清洁工一样,它默默地清理着不再使用的内存空间,确保我们的程序运行得既高效又稳定。但你真的了解垃圾回收是如何工作的吗?让我们一起探索这个看似简单却充满奥秘的过程,看看它是如何影响你的Java应用性能的。
255 5