GC 要完成的三件事情?
- 哪些内存需要回收?
- 什么时候回收?
- 如何回收?
如何判断一个对象可以被回收?
- 引用计数算法
- 可达性分析算法
引用计数法
说明:给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加1;当引用失效时,计数器值就减1;任何时刻对象的计数器为0时表示这个对象不再被使用了。
主流的Java虚拟机里面没有使用引用计数器进行内存管理。主要原因是因为其很难解决对象之间相互循环引用的问题。
/**
* 测试 object 相互引用 gc
*
* @author apple
*/
public class ReferenceCountGc {
public Object instance = null;
private static final int _1MB = 1024 * 1024;
/**
* 占内存用,在 GC 日志中看是否被回收
*/
private byte[] bigSize = new byte[2 * _1MB];
public static void testGC() {
ReferenceCountGc objA = new ReferenceCountGc();
ReferenceCountGc objB = new ReferenceCountGc();
objA.instance = objB;
objB.instance = objA;
objA = null;
objB = null;
System.gc();
}
}
可达性分析算法
以 GC Roots 对象作为起点,开始往下搜索,所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连时,就证明这个对象是不可用的。
如图所示,虽然 object5、object6、object7 是相互关联的,但是他们到 GC Roots 是不可达的,所以他们被判定为时可回收的对象。
在 Java 语言中, GC Roots 的对象包括:
- 虚拟机栈(栈中的本地变量表)中引用的对象
- 方法区中类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中 JNI 应用的对象
Java 引用的概念:
- 强引用
就是指在程序代码中普遍存在的,例如 new 的引用,只要强引用在,垃圾收集器就不会回收被引用的对象。 - 软引用
描述一些还有用但是并非必须的对象。软引用关联的对象,在系统将要内存溢出小hi我is你,会将这些对象列入回收范围中进行第二次回收。如果这次回收,还是没有足够的内存,那么内存溢出。
使用 SoftReference 类实现。 - 弱引用
描述非必须对象,但是比软引用更弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。无论当前内存是否够用,都会会都弱引用关联的对象。
使用 WeakReference 类实现。 - 虚引用
为一个对象设置虚引用关联的唯一目的就是能在这个对象被垃圾回收期回收时,收到一个系统通知。
使用 PhantomReference 类来实现。