2025-11-30 · garbage-collection
【Garbage Collection Series】GC 横向对比:Java vs Go vs Python vs Rust
多维度对比主流编程语言的内存管理策略,分析吞吐量、延迟与开发效率的权衡。
Java 是垃圾回收 (GC) 技术的集大成者。从最早的 Serial GC 到如今的 ZGC,JVM 的 GC 演进史就是一部 GC 技术的发展史。本文将深入探讨 Java GC 的核心算法与实现细节。
绝大多数 Java 对象都是“朝生夕死”的。基于这个观察,JVM 将堆内存划分为新生代 (Young Generation) 和 老年代 (Old Generation)。
分代收集的一个核心问题是:如何处理老年代对象指向新生代对象的引用? 如果在 Minor GC 时扫描整个老年代来查找这些引用,性能将无法接受。JVM 引入了 卡表 (Card Table) 技术。
写屏障伪代码 (Write Barrier Logic):
void oop_field_store(oop* field, oop new_value) {
*field = new_value; // 1. 更新引用
if (is_old_gen(field) && is_young_gen(new_value)) {
// 2. 写后屏障 (Post-Write Barrier)
// 计算卡表索引
size_t card_index = (uintptr_t)field >> CARD_SHIFT;
// 标记为脏
byte_map_base[card_index] = 0;
}
}CMS 是第一款真正意义上的并发收集器,目标是获取最短回收停顿时间。它基于标记-清除算法。
CMS 使用增量更新来解决并发标记时的漏标问题。 * 核心思想:当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。
G1 开创了面向局部收集的设计思路和基于 Region 的内存布局形式。
G1 将堆划分为多个 Region。每个 Region 都有一个 RSet,记录了”谁引用了我”。 * Point In:RSet 记录的是别的 Region 指向自己的指针。 * 价值:回收某个 Region 时,不需要扫描整个堆,只需要扫描该 Region 的 RSet 即可确定存活对象。
G1 使用 SATB 算法来维持并发标记的正确性,不同于 CMS 的增量更新。
SATB 写屏障伪代码:
void oop_field_store(oop* field, oop new_value) {
oop old_value = *field;
// 1. 写前屏障:记录旧值
if (gc_is_marking && old_value != null) {
enqueue(old_value); // 加入 SATB 队列,视为存活
}
*field = new_value; // 2. 更新引用
// 3. 写后屏障 (用于维护 RSet)
if (cross_region_ref(field, new_value)) {
update_remembered_set(field, new_value);
}
}SATB vs 增量更新: * CMS (增量更新): 关注引用的增加。 * G1 (SATB): 关注引用的删除 (保存旧引用,保证快照一致性)。
ZGC 是基于页 (Page) 的、不分代的(JDK 21之前)、低延迟垃圾收集器。
ZGC 将对象的状态信息直接存储在指针上,而不是对象头中。64位指针被划分为: * 0-41 bit: 对象地址 (4TB 支持) * 42-45 bit: 标志位 (Finalizable, Remapped, Marked1, Marked0)
ZGC 不使用写屏障来维护对象引用,而是使用读屏障。当程序读取一个对象引用时,ZGC 会检查指针颜色。
读屏障伪代码:
oop load_barrier(oop* ptr) {
oop ref = *ptr;
// 检查指针颜色是否正确 (Bad Color Check)
if (has_bad_mask(ref)) {
// 慢路径:修正指针 (Remap/Mark)
ref = slow_path_fix(ref);
// 更新内存中的指针,下次访问就是快路径
*ptr = ref;
}
return ref;
}| 特性 | CMS | G1 | ZGC |
|---|---|---|---|
| 算法 | 标记-清除 | 标记-整理 + 复制 | 标记-整理 (并发) |
| 并发保障 | 增量更新 (写后屏障) | SATB (写前屏障) | 读屏障 |
| 内存布局 | 分代 (物理连续) | Region (物理不连续) | Page (动态大小) |
| STW 目标 | 低 | 可控 (MaxGCPauseMillis) | < 1ms (JDK 21+) |
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · garbage-collection
多维度对比主流编程语言的内存管理策略,分析吞吐量、延迟与开发效率的权衡。
2025-11-30 · garbage-collection
深入分析 Go 语言的低延迟垃圾回收机制,包括三色标记法、混合写屏障以及 GC Pacing 调优。
2025-11-30 · garbage-collection
深入解析 Python (CPython) 的内存管理,包括引用计数机制和分代循环垃圾收集器。
2025-11-30 · garbage-collection
探索垃圾回收技术的最新进展,包括 ZGC 的染色指针、读屏障技术以及 AI 驱动的参数调优。
Java 是垃圾回收 (GC) 技术的集大成者。从最早的 Serial GC 到如今的 ZGC,JVM 的 GC 演进史就是一部 GC 技术的发展史。本文将深入探讨 Java GC 的核心算法与实现细节。
绝大多数 Java 对象都是“朝生夕死”的。基于这个观察,JVM 将堆内存划分为新生代 (Young Generation) 和 老年代 (Old Generation)。
分代收集的一个核心问题是:如何处理老年代对象指向新生代对象的引用? 如果在 Minor GC 时扫描整个老年代来查找这些引用,性能将无法接受。JVM 引入了 卡表 (Card Table) 技术。
写屏障伪代码 (Write Barrier Logic):
void oop_field_store(oop* field, oop new_value) {
*field = new_value; // 1. 更新引用
if (is_old_gen(field) && is_young_gen(new_value)) {
// 2. 写后屏障 (Post-Write Barrier)
// 计算卡表索引
size_t card_index = (uintptr_t)field >> CARD_SHIFT;
// 标记为脏
byte_map_base[card_index] = 0;
}
}CMS 是第一款真正意义上的并发收集器,目标是获取最短回收停顿时间。它基于标记-清除算法。
CMS 使用增量更新来解决并发标记时的漏标问题。 * 核心思想:当黑色对象插入新的指向白色对象的引用关系时,就将这个新插入的引用记录下来,等并发扫描结束之后,再将这些记录过的引用关系中的黑色对象为根,重新扫描一次。
G1 开创了面向局部收集的设计思路和基于 Region 的内存布局形式。
G1 将堆划分为多个 Region。每个 Region 都有一个 RSet,记录了”谁引用了我”。 * Point In:RSet 记录的是别的 Region 指向自己的指针。 * 价值:回收某个 Region 时,不需要扫描整个堆,只需要扫描该 Region 的 RSet 即可确定存活对象。
G1 使用 SATB 算法来维持并发标记的正确性,不同于 CMS 的增量更新。
SATB 写屏障伪代码:
void oop_field_store(oop* field, oop new_value) {
oop old_value = *field;
// 1. 写前屏障:记录旧值
if (gc_is_marking && old_value != null) {
enqueue(old_value); // 加入 SATB 队列,视为存活
}
*field = new_value; // 2. 更新引用
// 3. 写后屏障 (用于维护 RSet)
if (cross_region_ref(field, new_value)) {
update_remembered_set(field, new_value);
}
}SATB vs 增量更新: * CMS (增量更新): 关注引用的增加。 * G1 (SATB): 关注引用的删除 (保存旧引用,保证快照一致性)。
ZGC 是基于页 (Page) 的、不分代的(JDK 21之前)、低延迟垃圾收集器。
ZGC 将对象的状态信息直接存储在指针上,而不是对象头中。64位指针被划分为: * 0-41 bit: 对象地址 (4TB 支持) * 42-45 bit: 标志位 (Finalizable, Remapped, Marked1, Marked0)
ZGC 不使用写屏障来维护对象引用,而是使用读屏障。当程序读取一个对象引用时,ZGC 会检查指针颜色。
读屏障伪代码:
oop load_barrier(oop* ptr) {
oop ref = *ptr;
// 检查指针颜色是否正确 (Bad Color Check)
if (has_bad_mask(ref)) {
// 慢路径:修正指针 (Remap/Mark)
ref = slow_path_fix(ref);
// 更新内存中的指针,下次访问就是快路径
*ptr = ref;
}
return ref;
}| 特性 | CMS | G1 | ZGC |
|---|---|---|---|
| 算法 | 标记-清除 | 标记-整理 + 复制 | 标记-整理 (并发) |
| 并发保障 | 增量更新 (写后屏障) | SATB (写前屏障) | 读屏障 |
| 内存布局 | 分代 (物理连续) | Region (物理不连续) | Page (动态大小) |
| STW 目标 | 低 | 可控 (MaxGCPauseMillis) | < 1ms (JDK 21+) |
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · garbage-collection
多维度对比主流编程语言的内存管理策略,分析吞吐量、延迟与开发效率的权衡。
2025-11-30 · garbage-collection
深入分析 Go 语言的低延迟垃圾回收机制,包括三色标记法、混合写屏障以及 GC Pacing 调优。
2025-11-30 · garbage-collection
深入解析 Python (CPython) 的内存管理,包括引用计数机制和分代循环垃圾收集器。
2025-11-30 · garbage-collection
探索垃圾回收技术的最新进展,包括 ZGC 的染色指针、读屏障技术以及 AI 驱动的参数调优。