为了解决引用计数法无法解决循环引用
的问题,在Java中采取了 可达性分析法
。
该方法的基本思想是吧对象之间的赋值引用看作是成一个引用链,这些引用链的头部被称为GC Roots
,发生垃圾收集是,通过一系列的“GC Roots
”对象作为起点进行搜索所有引用链,如果在“GC Roots
”和一个对象之间没有可达路径,则称该对象是不可达的
。
不过要注意的是被判定为不可达的对象
不一定就会成为可回收对象
。
被判定为不可达的对象
要成为可回收对象
必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象
的可能性,则基本上就真的成为可回收对象
了。
说到GC roots(GC根),在JAVA语言中,可以当做GC roots的对象有以下几种:
- 虚拟机栈中的引用对象(方法的本地变量)
- 方法区中的类静态属性引用的对象
- 方法区中的常量引用的对象(声明为final的常量值)
- 本地方法栈中JNI的引用对象(方法的本地变量)
那么,可达性分析有没有问题(缺点)呢?
消耗大量时间
从前面可达性分析知道,GC Roots主要在全局性的引用(常量或静态属性)和执行上下文中(栈帧中的本地变量表);
要在这些大量的数据中,逐个检查引用,会消耗很多时间;
GC停顿
可达性分析期间需要保证整个执行系统的一致性,对象的引用关系不能发生变化;
导致GC进行时必须停顿所有Java执行线程 (称为 “Stop The World” );
(几乎不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的)
Stop The World:
是JVM在后台自动发起和自动完成的;
在用户不可见的情况下,把用户正常的工作线程全部停掉;
耗时和GC停顿
由于需要从GC Roots开始逐个检查引用,所以耗时是缺点之一,而且在此期间,需要保证整个执行系统的一致性,对象的引用关系不能发生变化,所以会导致GC进行时必须停顿所有Java执行线程(STW),所以这是缺点之二。
注:几乎不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的。