判断一个对象是否可回收
Java的内存管理子系统,是通过可达性分析算法来判定对象是否存活。
引用计数法
给对象添加一个引用计数器,每当有一个地方引用,计数器就加 1 。当引用失效,计数器就减 1 。任何时候计数器为 0 的对象就是不可能再被使用的。
引用计数法实现简单,效率高,但是目前主流的虚拟机中没有选择这个算法来管理内存,最主要的原因是它很难解决对象之前相互循环引用的问题。
相互引用:
/** * 将Main class设置为想要查看GC日志的类 * VM options : -XX:+PrintGCDetails */ public class ReferenceCountingGC { public Object reference = null; private static final int _1MB = 1024 * 1024; /** * 这个成员变量的唯一意义就是占点内存,以便能够在GC日志中看清楚是否有回收过 */ private byte[] bigSize = new byte[2 * _1MB]; public static void main(String[] args) { ReferenceCountingGC objectA = new ReferenceCountingGC(); ReferenceCountingGC objectB = new ReferenceCountingGC(); objectA.reference = objectB; objectB.reference = objectA; objectA = null; objectB = null; //假设在这行发生GC,objectA和objectB是否能够被回收 System.gc(); } } /** * [PSYoungGen: 8030K->872K(75776K)] 8030K->880K(249344K) * 如果使用引用计数算法,那么这两个对象将会无法回收。 * 而现在两个对象被回收了,说明Java使用的不是引用计数算法来进行标记的。 */
在Java领域,至少主流的Java虚拟机里面都没有选用引用计数算法来管理内存,主要原因是,必须要配合大量的额外处理才能保证正确的工作,比如单纯的引用计算很难解决对象之间相互循环引用问题。
可达性分析算法
通过一系列的称为 “GC Roots” 的对象作为起点集,从这些节点开始向下搜索,搜索过程所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连的话,则证明此对象时不可用的。
利用可达性分析算法判定对象是否可回收
对象object5,object6,object7虽然没有相互关联,但是他们到GC Roots是不可达的,因此他们判定为可回收对象
Java技术体系里面。固定可作为GC Roots的对象包括一下几种:
- 虚拟机栈中局部变量表中引用的对象
- 在方法区中类静态属性引用对象,比如类的引用型静态变量
- 方法区中的常量引用的对象
- 本地方法栈中 JNI 中引用的对象(Native方法)
- Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻对象(NullPointException,OutOfMemoryError)等,还有一些类加载器
- 所有被同步锁(synchronized关键字)支持的对象
ception,OutOfMemoryError)等,还有一些类加载器 - 所有被同步锁(synchronized关键字)支持的对象
- 反映Java虚拟机内部情况的JMXBean,JVMTI中注册回调,本地代码缓存等。