JVM垃圾回收机制(一)

本文介绍了Java垃圾回收机制中如何判断对象是否可回收,探讨了引用计数算法及其在Java中的局限性,以及可达性分析算法的工作原理,强调了Java并未采用引用计数法的原因在于无法处理循环引用问题。同时,列举了Java中作为GCRoots的对象类型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

垃圾回收机制并不是Java语言特有的产物,甚至其思想产生比Java历史更久远,直至Java的兴起才将这门“自动化”内存管理技术发扬光大。回忆一下Java内存运行时的各个区域,不熟悉的同学请移步JVM内存模型-详解。其中程序计数器,虚拟机栈,本地方法栈这3个区域是跟线程的生命周期保持一致的,空间的分配和回收都是具有确定性的,线程结束,内存自然可以跟着回收了,所以这些区域不用过多关注内存的回收。但是对于Java堆和方法区却天然存在不确定性,只有运行期间我们才知道创建了多少对象,哪个程序片段会创建对象,所以这部分内存才是JVM垃圾回收机制所关注的区域。

判定对象是否存活

既然我们想要回收内存,那么首先要确认的就是哪些对象可以回收,哪些并不能回收,即我们要找到“存活”的对象,或者找到已经“死亡”的对象,简单来收,就是回收没有任何引用的对象,并保留还在使用中的对象。通常的,对于判单对象是否存活,我们会提到两个算法:引用计数算法和可达性分析算法。
对引用概念不清楚的同学可以移步:Java中的引用类型-简述

引用计数算法

简单来说,引用计数法(Reference Counting)的思想就是在对象中引入一个引用计数器,当有新的引用时,计数器加一,当引用失效时,计数器减一。为零时则表明该对象没有被使用,即对象已“死亡”,可以安全回收。虽然该算法需要有额外的计数器内存开销,但是其原理简单,判定的效率也高。经典使用案例,例如微软的COM,Flash Player,Python等使用了该算法来进行内存管理。但是在Java领域,主流的JVM都没有采用这种算法,一个很主要的原因就是简单的引用计数算法无法解决循环依赖问题。如下图:
循环引用
其实这两个对象已经没有其他对象在使用了,但是由于计数器数值不为零,导致判定为存活,造成内存浪费。
下面我们来看一段代码:

public class GCTest {

    GCTest ref = null;

    /**
     * 加大对象内存占用,以便于观察
     */
    private static final int oneMB = 1024 * 1024;
    private byte[] arr = new byte[oneMB * 2];

    public static void testGC() {
        GCTest A = new GCTest();
        GCTest B = new GCTest();

        A.ref = B;
        B.ref = A;
        
		A = null;
        B = null;

        // 调用GC观察
        System.gc();
    }

    public static void main(String[] args) {
        testGC();
    }
}

注:idea中观察GC日志请添加虚拟机参数:-XX:+PrintGCDetails
运行结果
运行结果
可以看到,并没有因为对象A和对象B的循环引用,而放过清理,这也证明了JVM未采用引用计数法来判定对象是否死亡。

可达性分析算法

基本思想:可达性分析算法(Reachability Analysis)通过一系列“GC Roots(根对象)”作为起始节点集,根据引用关系向下搜索,称搜索走过的路径为“引用链”(Reference Chain),若对象跟GCRoot之间不存在引用链的话,则判定该对象可回收,用图论的方式来描述就是该对象不可达。如下图:
可达性分析示意图
可以清楚看到,虽然obj6、obj7、obj8之间有引用也会被判定为死亡。
在Java中一般作为GC Roots的对象包括:

  • 在虚拟机栈(栈帧中的本地变量表)中引用的对象。
  • 方法区中类静态属性引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中,Native方法引用的对象。
  • JVM内部的引用。
  • 被同步锁持有的对象。
  • 反映JVM内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。

除去以上固定的GC Roots集合外,也可以临时加入其他对象,这跟选择的收集器以及收集的区域有关。

小结

本文简单描述了垃圾回收的前期准备,即判断对象是否可回收的两种算法。这将为后期垃圾收集算法打下基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值