判断对象是否存活算法

Posted by hang.li on November 20, 2022

引用计数算法

  • 对象每当被引用一次在其头部计数器加一,引用失效,头部减一,计数器为0时代表该对象没有任何引用,视为垃圾。
  • 缺点:无法解决循环引用问题。

    可达性分析(java使用)

  • 通过GC Roots沿引用开始搜索,没有被扫描到的即视为垃圾。
  • GC时常说的标记过程就是应用可达性分析算法进行标记;注,标记标记到的都是存活的对象。

    java中的GC Roots

    1. 虚拟机栈中的引用的对象
    2. 常量池中的引用(jdk7及以前中的String对象全部分配在StringPool中,jdk8开始的StringPool可能是一个指向堆中String对象的引用)。
    3. 本地方法栈中使用的对象
    4. 虚拟机内部的引用,如基本数据类型的class对象,常驻的异常对象,系统类加载器等。
    5. 被synchronize持有的对象
    6. jvm内部信息的一些对象
    7. 分区收集时,其他区的引用。(如:G1中对一个Region收集时,其他Region的引用)

      并发下的可达性分析

  • gc与用户线程并发会产生的问题(如:a->b->c):

    产生的问题

    并发问题一

    1. c扫描结束
    2. c对象被gc标记为存活对象
    3. ==b->c被用户线程取消==(gc不知道)
    4. gc清理垃圾(c没有被清理掉,浮动垃圾)

      并发问题二

    5. a扫描结束,b扫描中
    6. ==b->c被用户线程取消==(正在扫描b,gc知道),c被标记为垃圾
    7. ==a->c建立引用关系==(gc不知道)
    8. gc清理垃圾(c被清理)

      解决方案

      增量更新

      ==a到c建立引用关系==时,a会被标记为需要被重新扫描的状态,并发标记后,以a为根,重新扫描一次。不能处理并发问题一

      原始快照

      ==b到c断开引用关系==时,b会被标记为需要被重新扫描的状态,以b为根重新按照扫描前的快照重新扫描,当扫描到c时,借助OopMap记录能够判断c被引用,将c标记为存活对象。