垃圾收集器如何判断内存是否需要回收
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堆中,而方法区也是有回收垃圾的,主要回收废弃常量和无用的类。