引用计数算法
基本思路
在对象中添加一个引用计数器,每当有一个地方引用它时,计数器值就加一;当引用失效时,计数器值就减一;任何时刻,计数器值为零的对象就是不可能再被使用的。
优点/缺点
引用计数算法的原理简单,执行高效,但是主流的 Java 虚拟机中都没有选择引用计数算法来进行内存管理,主要原因是这个看似简单的算法其实有很多例外情况需要考虑,必须配合大量额外处理才能保证算法正常地工作,例如在涉及对象之间互相循环引用的问题。
经典案例
Netty 中的 ByteBuf
使用了引用计数算法,提供了优于 JVM GC 和引用队列的高效的实时性。
可达性分析
基本思路
当前主流程序语言的内存管理都是通过可达性分析(Reachability Analysis)算法来判定对象是否存活的。
通过一系列的「GC Roots」的根对象作为起始节点,从这些节点开始根据引用关系向下搜索,搜索过程所走过的路径被称为「引用链(Reference Chain)」,如果某个对象到 GC Roots 间没有任何引用链相连,或者用图论的话来说就是从 GC Roots 到这个对象不可达,则证明此对象是不可能再被使用的。
GC Roots
-----------------------------------------------
|
object1 object5
/ \ / \
object2 object3 object6 object7
|
object4
在 Java 技术体系中,固定可作为 GC Roots 对象包括以下几种:
- 在虚拟机栈中引用的对象,例如各个线程被调用的方法堆栈中使用到的参数、局部变量、临时变量等;
- 在方法区中类的静态属性引用的对象,例如 Java 类的引用类型的静态变量;
- 在方法区中常量引用的对象,例如字符串常量池中的引用;
- 在本地方法区中 JNI 引用的对象;
- 在 Java 虚拟机内部的引用,例如基本数据类型对应的 Class 对象,一些常驻的异常对象,系统类加载器等;
- 所有被同步的锁(synchronized 关键字)持有的对象;
- JMXBean、JVMTI 中注册的回调、本地代码缓存等
- ……