垃圾收集器

垃圾收集器如何判断内存是否需要回收

java的内存分配有:程序计数器、虚拟机栈、本地方法栈、java堆、方法区
其中程序计数器、虚拟机栈、本地方法栈随着线程而生、线程而死,而内存的分配在类结构确定下来就已经确定了,在内存大小和回收时机上是确定的。而java堆和方法区就比较麻烦,我们只有在程序运行时,才知道要分配多大的空间,而什么时候创建和回收也是不确定的。

回收策略

引用计数法

给对象添加一个引用计数器,每当有一个地方引用它,就给计数器+1;引用失效,计数器-1,当引用技术器为0时就判定对象可以回收。

可达性分析

引用计数法是不靠谱的,如果两个对象中各有一个字段引用对方对象,而对象本身却已经不可能再被访问了,可是引用计数法都不为0,在这种情况下GC回收器还是会回收内存的。代码如下:

public class ReferenceCountingGC {
    public Object instance = null;

    public static void main(String[] args) throws Exception {
        ReferenceCountingGC objA = new ReferenceCountingGC();
        ReferenceCountingGC objB = new ReferenceCountingGC();
        objA.instance = objB;
        objB.instance = objA;

        objA = null;
        objB = null;

        System.gc();
    }
}

所以在java语言中并没有采用引用技术法作为回收策略,使用了可达性分析算法
可达性分析算法中,定义了一种名为“GC Root”的对象,对象之间的引用构成图,凡是被“GC Root”为起点,走过的路径称为引用链,引用链上的对象不会被回收。
哪些是“GC Root”对象呢?

  • 虚拟机栈(本地变量表)中引用的对象。
  • 方法区中类的静态变量引用的对象。
  • 方法区中常量引用的对象。
  • 本地方法栈中引用的对象。

回收方法区

上面说到的对象回收是发生在java堆中,而方法区也是有回收垃圾的,主要回收废弃常量和无用的类

推荐阅读更多精彩内容