垃圾回收算法中主要有两种算法判定哪些对象是否可达,哪些可以被回收。它们分别是引用计数法、可达性分析法。
重点介绍了三色标记法,它是可达性分析算法的一种具体实现策略。三色标记法是一种改进的标记过程,用于实现可达性分析中的标记步骤,特别适合并发垃圾收集器。
1、引用计数法
引用计数法是一种垃圾回收策略,主要用于管理对象的内存分配和释放。核心思想是通过计数每个对象的引用次数判定该对象是否可以回收。当一个对象的引用计数变为零时,表示没有其他对象引用它,可以安全地回收该对象占用的内存。
1.1、引用计数法的工作机制
(1) 引用计数增加:每当有一个新的引用指向对象时,该对象的引用计数加1。
(2) 引用计数减少:当某个引用被删除或指向其他对象时,原对象的引用计数减1。
(3) 内存回收:当对象的引用计数降为零时,表示没有任何其他对象引用它,内存管理器可以回收它的内存。
1.2、引用计数法的优缺点
优点
-
即时性:引用计数法可以及时回收没有引用的对象,不需要等到垃圾回收器的运行周期。
-
简单直观:容易理解和实现,因为每次引用变化都更新计数器。
缺点
-
循环引用:引用计数法无法处理循环引用的问题。如果两个或多个对象相互引用,但没有其他对象引用它们,引用计数不会降为零,导致内存泄漏。例如,A 对象引用 B,B 对象也引用 A,两者的引用计数都不会降为零。
-
维护开销:引用计数的增减会带来一定的性能开销,尤其是在对象频繁被引用或解除引用的情况下。
1.3、引用计数法的应用场景
引用计数法在现代 JVM 中不常见,但可以在一些特殊场景或手动内存管理中使用。比如Python 的内存管理主要依赖引用计数法。
2、 可达性分析法
可达性分析法 是现代垃圾回收器(比如 JVM )中常用的一种算法,用来判断哪些对象是“存活”的,哪些是“垃圾”可以被回收。它通过从一组称为GC Roots的根对象出发,找到所有可以被直接或间接引用的对象。不可达的对象视为垃圾,等待回收。
2.1、可达性分析法的工作原理
(1) 确定 GC Roots:GC Roots 是一组特殊的、始终可以被直接访问的对象,通常包括:
-
程序栈中引用的对象(例如局部变量、方法调用链)。
-
静态属性引用的对象(静态变量)。
-
JNI 引用的对象(即本地方法中的引用)。
(2) 从 GC Roots 出发进行遍历:从 GC Roots 开始,遍历整个对象图。每遇到一个对象,就标记它为可达对象,再递归访问该对象引用的其他对象。
(3) 判断对象是否可达:
-
如果某个对象可以从 GC Roots 路径访问到,表示它是可达的,是活跃的对象。
-
如果某个对象无法通过 GC Roots 路径访问到,表示它是不可达的,可以被回收。
2.2、可达性分析法的优缺点
优点
-
可以处理循环引用:可达性分析法不依赖于引用计数,不会因对象相互引用(形成循环)而导致无法回收。
-
灵活:现代垃圾回收器可以通过这种算法实现分代回收、标记清除、标记压缩等不同的策略。
缺点
-
性能开销:需要遍历对象图,尤其是对象图非常庞大时,分析过程可能会消耗较多时间和资源。
-
暂停应用程序:在传统的 Stop-the-World 垃圾回收中,可达性分析会暂停应用,影响实时性。因此现代垃圾回收器会使用多线程、增量式或并发方式优化这个过程。
2.3、可达性分析法的应用场景
可达性分析算法是 JVM 中默认的垃圾回收判定方法,被广泛应用在 HotSpot VM 的各大垃圾收集器中,如 G1、Shenandoah、ZGC 等。
3、三色标记法
三色标记法是一种用于垃圾回收的标记算法,常用在标记-清除和并发垃圾收集器中,是可达性分析算法在并发场景中的一种优化实现方式。它通过三种颜色(白色、灰色和黑色)标记对象的状态,跟踪哪些对象是可达的,哪些可以被回收。该算法不仅可以准确地判断存活对象,还能有效地解决并发垃圾回收中的问题,如“浮动垃圾”和“漏标”等。
3.1、三色标记法的颜色含义
白色(未访问):表示未被垃圾收集器访问的对象。初始状态下,所有对象都是白色的。
灰色(正在访问):表示对象已被访问,但它引用的对象还未完全访问。灰色对象必须继续扫描其引用,直到它的所有引用对象都被标记后才能变为黑色。
黑色(已访问完毕):表示对象已被访问,并且它引用的所有对象都已被访问完毕,不再需要进一步处理。
3.2、三色标记法的工作流程
(1) 初始化阶段:从 GC Roots 出发,将所有直接引用的对象标记为灰色,剩下的对象仍然是白色。
(2) 扫描阶段:
-
每次从灰色对象集合中取出一个对象,将其引用的对象标记为灰色(如果引用对象还未被标记)。
-
该灰色对象被扫描完后,标记为黑色,表示不再需要进一步处理。
(3) 结束阶段:当灰色对象集合为空时,扫描结束。此时,所有黑色对象表示可达对象,而白色对象则是不可达的,可以被回收
3.3、三色标记法在并发收集中的问题
在并发垃圾回收中,三色标记法可能会因为用户线程的并发操作而遇到两种问题:
(1) 浮动垃圾:由于垃圾回收和应用程序同时运行,可能会出现一部分垃圾在收集结束前被标记为黑色,导致这些垃圾未被立即回收。这种“浮动垃圾”会在下一次回收时被清理掉,但会占用内存直到下次回收。
(2) 漏标:如果一个灰色对象 A 引用了一个白色对象 B,而用户线程在 A 变为黑色后将 B 从 A 移动到某个黑色对象 C,那么垃圾回收器可能会忽略 B,使 B 被错误地回收。
3.4、解决漏标问题的两种方式
(1) 增量更新:当黑色对象增加新引用时,将新引用的对象重新标记为灰色,以确保其不会被误回收。
(2) 写屏障的快照视图:在垃圾回收开始时,快照所有存活对象,并使用写屏障来记录所有被修改的引用,可以避免漏标问题。
3.5、三色标记法的优缺点
优点
-
并发性:支持并发回收,不需要长时间的应用程序暂停。
-
可达性准确:有效解决循环引用和可达性判断问题。
缺点
-
浮动垃圾:并发收集中,可能会产生一些浮动垃圾,增加下一次垃圾回收的负担。
-
性能开销:需要维护颜色状态,增量更新或写屏障操作会增加额外的性能开销。
3.6、三色标记法的实际应用
现代的垃圾回收器(如 G1、Shenandoah 和 ZGC)都会基于三色标记法进行可达性分析,确保高效的并发回收。
4、我的公众号
敬请关注我的公众号:大象只为你,持续更新技术知识......
原文始发于微信公众号(大象只为你):JVM中有哪些算法能判定对象可回收?
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论