JVM垃圾回收相关算法

垃圾标记阶段

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

引用计数法 (java没有采用)

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

循环引用导致的内存泄漏情况:

JVM垃圾回收相关算法证明: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没有采用引用计数算法 .

JVM垃圾回收相关算法

 

 



上一篇:关于String类型是否是引用类型


下一篇:电商系统 常用代码段