判断对象是否存活
垃圾回收器在对堆进行垃圾回收前,首先要判断这些对象是否还是存活状态。这就需要以下的判断方法:
-
1. 引用计数法(Python、PHP使用)
每当对象被引用一次,计数器 +1;当引用失效,计数器 -1;当计数器为0时,对象已死,回收。
- java不采用,因为该方法无法对象的解决循环引用的问题。
- 循环引用:对象之间的引用,对象A中的一个属性指向对象B,对象B中的一个属性指向A,两个之间循环依赖,两个的计数器都为1,但是栈空间没有任何对象引用他。
循环引用示例:
/**
* 引用计数法
* JVM参数 :-XX:+PrintGC 打印GC使用时的状态,不打印无法看出是否回收
* Author:qqy
*/
public class TestGc {
public Object instance=null;
//编译器在编译代码的时候就将值计算好了,效率更高
private static final int _2MB=1024*1024*2;
private byte[] data=new byte[_2MB];
public static void main(String[] args) {
TestGc test1=new TestGc();
TestGc test2=new TestGc();
test1.instance=test2;
test2.instance=test1;
test1=null;
test2=null;
//执行垃圾回收
System.gc();
}
}
运行结果:
运行结果是垃圾回收器的日志信息,7M回收后 0.8M ,0.8M回收后0.6M。如果GC触发后没有回收,前后两个数字应该是相等的或者差距不大 -> 虚拟机没有因为这两个对象互相引用就不回收他们 -> Java中不适用引用计数法
-
2. 可达性分析算法
当一个对象无法通过引用链关系(通过一系列称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径)追溯到GC Roots对象上去,则称该对象不可达,即不可用 -> 被垃圾回收。
- 可作为GC Roots的对象包含下面几种:
- 虚拟机栈中引用的对象 (局部变量)
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI (Native方法)引用的对象
- JNI-> JavaNativeInterface :Java本地接口
- 系统对接,1.通过网络通信,2.通过Java语言调用C语言的API(通过JNI实现)
- 代码中出现过多的静态属性,会导致内存泄漏 -> 静态属性属于GC Roots,可达,无法被回收 -> 内存泄漏