JVM中的垃圾回收算法

本文详细介绍了JVM中的垃圾回收算法,包括标记阶段的引用计数算法和可达性分析算法,以及垃圾清除阶段的标记-清除、复制、标记-压缩等算法。此外,还讨论了对象的finalization机制、GC Roots的确定以及使用MAT和JProfiler工具分析GC Roots的方法。文章强调了分代收集算法的重要性,以及增量收集和分区算法G1回收器如何减少系统停顿时间。
摘要由CSDN通过智能技术生成

1、垃圾标记阶段

  • 对象存活判断:在堆中存放着几乎所有的java对象实例,在GC执行垃圾回收之前,首先需要区分内存中那些是存活对象,哪些是已经死亡的对象,只有被标记为死亡的对象,GC才会在执行垃圾回收的时候,释放其所占用的内存空间,因此这个过程我们可以称为垃圾标记阶段
  • 那么JVM中究竟如何标记一个死亡对象呢? 简单来说,当一个对象已经被不在被任何存活的对象继续引用,就可以宣判已经死亡
  • 判断对象存活一般有两种方式:引用技术算法和可达性分析算法

1、2 引用计数算法(Java没有采用)

  • 引用计数算法(Reference Counting) 比较简单,对每个对象保存一个整形的应用计数器属性,用于记录对象的被引用情况
  • 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减1。只要对象A的引用计数器的值为0,即表示对象A不可能再被使用,可进行回收。
  • 优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟性。
  • 缺点:
    • ➢它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
    • ➢每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
    • ➢引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一 条致命缺陷,导致在Java的垃圾回收器中没有使用这类算法。
      循环引用导致的内存泄露问题
      在这里插入图片描述
      证明:Java使用的不是引用技术算法
/**
 * -XX:+PrintGCDetails
 * 证明:java使用的不是引用计数算法
 */
public class RefCountGC {
   
    //这个成员属性唯一的作用就是占用一点内存
    private byte[] bigSize = new byte[5 * 1024 * 1024];//5MB,仅仅意味着只要创建我这个RefCountGC对象实例,就会占用5M的堆空间

    Object reference = null;

    public static void main(String[] args) {
   
        RefCountGC obj1 = new RefCountGC();
        RefCountGC obj2 = new RefCountGC();

        obj1.reference = obj2;
        obj2.reference = obj1;

        obj1 = null;
        obj2 = null;
        //显式的执行垃圾回收行为
        //这里发生GC,obj1和obj2能否被回收?能,证明Java没有采用引用计数算法
        System.gc();

        try {
   
            Thread.sleep(1000000);
        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }
    }
}

引用技术算法的弊端:即使把obj1 一reference和obj2 一reference(栈引用)置null。 则在Java堆当中的两块内存依然保持着互相引用,无法回收。
但是把obj1 一reference和obj2 一reference置为null之后,如果显示的去调用System.gc();这里将会发生GC,回收堆中bj1和obj2实体。从而证明Jlava没有采用引用计数算法 .
在这里插入图片描述

1、2 可达性分析算法

也叫根搜索算法或追踪性垃圾收集

  • 相对于引用计数算法而言,可达性分析算法不仅同样具备简单和执行高效率等特点,更重要的是该算法可以有效的解决在引用计数算法中循环引用的问题,防止内存泄露的发生
  • 相较于引用计数算法,这里的可达性分析就是java、c#选择的。种类型的垃圾收集通常也叫作追踪性垃圾收集(Tracing GarbageCollection)。
  • 所谓"GC Roots"根集合就是一组必须活跃的引用。
  • ➢可达性分析算法是以根对象集合(GCRoots)为起始点,按照从上至下的方式搜索被根对象集合所连接的目标对象是否可达。
  • ➢使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或间接连接着,搜索所走过的路径称为引用链(Reference Chain)
    在这里插入图片描述

1、3 GC Roots

在java语言中,GC Roots对象包括以下几类元素
1、虚拟机栈中引用的对象:➢比如:各个线程当中被调用的方法中使用到的参数、局部变量等。
2、.本地方法栈内JNI(通常说的本地方法)引用的对象
3、方法区中类静态属性引用的对象➢比如:Java类的引用类型静态变量

Class Dog {
   
    private static Object tail;
} 

4、方法区中常量引用的对象:➢比如:字符串常量池(string Table) 里的引用

Class Dog {
   
    private final Object tail;
} 

5、所有被同步锁synchronized持有的对象
6、Java虚拟机内部的引用:➢基本数据类型对应的Class对象,一些常驻的异常对象(如: NullPointerException、OutOfMemoryError) ,系统类加载器。、
7.反映java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等.
8、除了这些固定的GCRoots集合以外,根据用户所选用的垃圾收集器以及当 前回收的内存区域不同,还可以有其他对象“临时性”地加入,共同构成完整GC Roots集合。比如:分代收集和局部回收(Partial GC)。
➢如果只针对Java堆中的某一块区域进行垃圾回收(比如:典型的只针 对新生代),必须考虑到内存区域是虚拟机自己的实现细节,更不是孤立封闭的࿰

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值