java垃圾回收机制

前言

  • 垃圾收集GC(Garbage Collection)是Java语言的核心技术之一,GC通过确定对象是否被活动对象引用来确定是否收集该对象。GC首先要判断该对象是否是可以收集。两种常用的方法是引用计数算法和对象引用遍历。
  • 垃圾回收机制主要作用于java堆(Heap),也就是jvm用于存放对象实例的地方.

引用计数算法

引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象(不是引用)都有一个引用计数。当一个对象被创建时,且将该对象分配给一个变量,该变量计数设置为1。当任何其它变量被赋值为这个对象的引用时,计数加1(a = b,则b引用的对象+1),但当一个对象的某个引用超过了生命周期或者被设置为一个新值时,对象的引用计数减1。任何引用计数为0的对象可以被当作垃圾收集。当一个对象被垃圾收集时,它引用的任何对象计数减1。

  1. 优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序不被长时间打断的实时环境比较有利。
  2. 缺点: 无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0.如:
public class ReferenceCountingGC{
    public Object instance = null;
    public static void testGC(){
        ReferenceCountingGC objA = new ReferenceCountingGC ();
        ReferenceCountingGC objB = new ReferenceCountingGC ();
        objB.instance = objA;
        objA.instance = objB;
        objA = null;
        objB = null;
        System.gc();
    }
}

要是虚拟机用了引用计数算法,那么上面的objA和objB会不会回收呢?

可达性分析算法(Rearchability Analysis)

早期的JVM使用引用计数,现在在主流的商用的程序语言中,都是称通过可达性分析算法来判断对象是否还存活着。这个算法是通过一系列的“GC roots”的对象作为起点,从这些节点向下搜索,搜索所经过的路径称为引用链,当一个对象到GC roots没有任何引用链相连的时候。则此对象是不可用的。不可用的对象则是JVM判定为可回收的对象。
在java中,可作为gc roots的对象包括下面几种:

  • 虚拟机栈中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI引用的对象

就算是在可达性分析算法是不可达的对象,也不是非死不可,现在它们只是被“怀疑”,要真正宣告一个对象死亡,至少要经过两个阶段:在可达性分析的时候,要是不可达,那么它会被第一次标记并且进行一次筛选,筛选的条件是此对象有没有必要执行finalize()方法,当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过。那么,此对象就没有必要执行finalize()方法。
当一个对象被判定为有必要执行finalize()方法的时候,它就会被放到一个F-Queue的队列中,并且稍后会有一个由虚拟机自动创建的线程来执行它,而且在执行它的时候,虚拟机不保证会等待它运行结束,这是因为要是finalize()里面有死循环或者什么的就麻烦了,就会堵塞队列,有时会导致垃圾回收系统崩溃。稍后GC还会再次对F-Queue进行小规模地第二次标记,如果这次不幸成功被标记,那么它基本上真的就会被回收了。上面说了,finalize()不保证被完全执行,所以我们在开发中,最好不要用它来关闭资源什么的,因为try finally能更好地完成这项工作,所以建议大家忘记这个方法。

参考资料

  • JVM GC垃圾回收机制
  • 《深入理解java虚拟机》

你可能感兴趣的:(java垃圾回收机制)