主流的垃圾回收主要分两大类:引用计数和可达性分析。
引用计数法
引用计数的实现很简单,它的思想就是给一个对象增加一个引用计数器,每当一个新的对象引用它时就给计数器加1,不引用了就减1,当计数器为0时即可认为对象无用了,可进行回收。
这个思想很简单,而且很多语言的底层(如Swift,Python)都是基于引用计数法进行回收的。但是引用计数法有一个很大的缺陷:它无法解决循环引用的问题,比如A引用B,B引用A,这样两对象的引用计数器永远不为0,两对象不能被回收,从而造成内存不能被及时清理。
JVM没有使用引用计数法,而是使用了可达性分析来进行GC。
题外话:C++ 11的智能指针就是基于引用计数的,它提供了weak_ptr
来解决循环引用的问题。(类似于Java中的WeakReference
,作用类似)
可达性分析
可达性分析是基于图论的分析方法,它会找一组对象作为GC Root(根结点),并从根结点进行遍历,遍历结束后如果发现某个对象是不可达的(即从GC Root到此对象没有路径),那么它就会被标记为不可达对象,等待GC。比如,假设下图中obj1位GC Root,那么obj5和obj6就是不可达的:
哪些对象可以作为GC Root
能作为GC Root的对象必定为可以存活的对象,比如全局性的引用(静态变量和常量)以及某些方法的局部变量(栈帧中的本地变量表)。
以下对象通常可以作为GC Root:
- 存活的线程
- 虚拟机栈(栈桢中的本地变量表)中的引用的对象
- 方法区中的类静态属性以及常量引用的对象
- 本地方法栈中JNI引用的局部变量以及全局变量