JVM怎么判断对象是否存活

JVM怎么判断对象是否存活

  • 引用计数算法
    • 引用计数算法比较简单,对每个对象保存一个整型的引用计算器属性。用于记录对象背应用的情况。
    • 对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器就加1;当引用失效时,引用计数器就减少1.只要对象A的引用计数器的值为0,便表示对象A不可能再被使用,可进行回收。
    • 优点:实现简单,垃圾对象便于辨识;判定效率高,回收没有延迟。
    • 缺点:
      • 它需要单独的字段存储计数器,这样的做法增加了存储空间的开销。
      • 每次赋值都需要更新计数器,伴随着加法和减法操作,这增加了时间开销。
      • 引用计数器有一个严重的问题,即无法处理循环引用的情况。这是一条致命缺陷,导致java的垃圾回收器中没有使用这类的算法

  • 可达性分析
    • 基本思路:
      • 可达性分析算法是以根对象集合为起点,按照从上至少的方式搜索被根对象集合所连接的目标对象是否可达。
      • 使用可达性分析算法后,内存中的存活对象都会被根对象集合直接或者间接连接着,搜索所走过的路径称为引用链。
      • 如果目标对象没有任何引用链相连,则不可达的,就意味着该对象已经死亡,可标记为垃圾对象。
      • 在可达性分析算法中,只有能够被根对象集合直接或者间接连接的对象才是存活对象。

在Java语言里,可作为GC Roots对象的包括如下几种:
a.虚拟机栈(栈桢中的本地变量表)中的引用的对象
b.方法区中的类静态属性引用的对象
c.方法区中的常量引用的对象
d.本地方法栈中JNI的引用的对象

注意:如果要使用可达性分析算法来判断内存是否可回收,那么分析工作必须在一个能保障一致性的快照中进行。这点不满足的话分析结果的准确性就无法保证。

这点也是导致GC进行时必须STW的一个重要原因。即使是号称不会发生停顿的CMS收集器中,枚举根节点时也是必须停顿的。

  • finalization机制
    • 概述:当垃圾回收器发现一个没有引用指向一个对象,即:垃圾回收此对象之前,总会先调用这个对象的finalize()方法。它是允许被子类重写的,用于对象被回收时进行资源释放。通常在这个方法中进行一些资源释放和清理的工作,比如关闭文件,套接字和数据库的连接。
    • 不要主动调用finalize()方法的原因。
      • 在finalize()时可能导致对象复活。
      • finalize()方法的执行时间没有保障,它完全由GC线程决定,极端情况下,若不发生GC,则finalize()将没有执行的机会。
      • 一个槽糕的方法会影响GC性能
    • 三种状态:
      • 可触及的:从根节点开始,可以到达这个对象。
      • 可复活的:对象的所有引用都被释放,但是对象有可能在finalize()中复活。
      • 不可触及的:对象的finalize()被调用,并且没有复活,那么就会进入不可触及状态。不可触及的对象不可能被复活,因为finalize()只会被调一次。
    • 标记的2次过程:
      • 如果对象A在GC Roots没有引用链,则进行第一次标记。
      • 进行筛选,判断对象是否有必要执行finalize()方法。
        • 如果对象A没有重写方法,或者已经被调用过了,则被认为不可触及的。
        • 如果重写了方法,而且没有被执行,那么对象A会被插入到F-Queue队列中,由一个虚拟机自动创建的线程触发它的finalize()方法。
        • finalize()方法是对象脱逃死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次小规模标记,如果对象要在finalize()中成功拯救自己----只要重新与引用链上的任何的一个对象建立关联即可,譬如把自己赋值给某个类变量或对象的成员变量,那在第二次标记时它将移除出“即将回收”的集合。如果对象这时候还没逃脱,那基本上它就真的被回收了。
posted @ 2020-12-15 22:26  天宇轩-王  阅读(184)  评论(0编辑  收藏  举报