深入理解JAVA虚拟机(三)详解JVM对象的存活判定算法

​ 上一节详细讲解了JVM中对象的创建过程,这节讲解对象存活的判定,即对象在什么情况下会判定为“死亡”,从而被JVM垃圾回收。

  • 引用计数算法

    ​ 这种算法很简单,就是计算当前对象被引用数,当对象的引用计数器等于0的时候,就判定对象“死亡”。有一些语言,如FlashPlayer、Python、Squirrel等使用该算法进行内存管理,但是主流的JVM没有采用该算法,因为它无法解决对象互相引用的问题,以下代码演示对象互相引用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class JVMObjectBackDemo_31 {
    private Object instance = null;
    private static final int _1MB = 1024 * 1024;
    private byte[] bigsize = new byte[2 * _1MB];
    @Test
    public void testGc(){
    JVMObjectBackDemo_31 obj1 = new JVMObjectBackDemo_31();
    JVMObjectBackDemo_31 obj2 = new JVMObjectBackDemo_31();
    obj1.instance = obj2;
    obj2.instance = obj1;
    obj1 = null;
    obj2 = null;
    System.gc();
    }
    }

    ​ 通过查看GC日志 [Full GC (System.gc()) [PSYoungGen: 8092K->0K(57344K)] ,可以看到虽然对象存在互相引用,但是JVM垃圾回收还是将对象回收了,因为JVM(HotSpot)使用的不是引用技术算法。

    Intellij idea可以通过下面的配置记录gc日志:-XX:+PrintGC -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gc.log

    设置1

    设置1

  • 可达性分析算法

    主流对象判活算法,通过“GC Roots”对象做为起点,向下搜索,搜索路径称为“引用链”,如果一个对象到“GC Roots”没有任何引用链,即不可达,可判断对象是不可用的。以下可做为“GC Root”对象:

    • 虚拟机栈中引用的对象;

    • 方法区中类静态属性引用的对象;

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

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

  • 当对象不可达时,对象“死亡”过程

    即使在可达性分析算法中不可达的对象,也并非“非死不可”,看下面“宣告死亡”流程:

    对象回收流程

    • 可以将finalize()方法看作对象的一次“自我拯救”的机会,这个机会只有一次,当对象不可达时,如果这个机会没有使用过,则放入F-Queue队列。

    • JVM自动创建一个低优先级的Finalizer线程,去执行F-Queue队列,即去执行队列里对象的finalize()方法,如果对象“自我拯救”成功,将对象移出“即将回收”集合,但同时对象的这个唯一的机会也被使用了,下次再不可达时,将直接被回收。

坚持原创技术分享,您的支持将鼓励我继续创作!
分享