scavenge算法是v8专为新生代设计的复制式回收机制,通过将存活对象从from空间复制到to空间并清空from空间,实现毫秒级回收且无碎片;其高效源于仅扫描一半空间、只处理少量存活对象、避免清理与整理开销。

Scavenge 算法是 V8 引擎专为新生代(Young Generation)设计的快速垃圾回收机制,核心目标是高效处理大量“短命”对象——也就是刚创建、很快就被丢弃的对象。它不靠标记和扫描,而是用空间换时间,通过复制存活对象来完成回收,整个过程几乎不产生内存碎片。
Scavenge 的基本结构:两个半空间
新生代堆被均分为两个大小相等的区域:From 空间 和 To 空间。新对象默认分配在 From 空间;当 From 空间快满时,触发 Scavenge 回收:
- 只遍历 From 空间中所有对象,检查是否仍被引用(即是否“可达”)
- 把所有存活对象**复制**到 To 空间(不是移动,是全新分配+拷贝)
- 复制完成后,From 空间被整体清空,To 空间变成新的 From 空间,原 From 变成新的 To 空间
为什么复制比清理更快?
Scavenge 不需要逐个清理死亡对象,也不需要维护空闲链表或整理碎片。它的效率来自三点:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
- 只需扫描一半空间(From),且只处理存活对象(通常占比很低,
- 复制过程天然实现内存整理——To 空间中的对象紧密排列,无碎片
- 无需标记阶段,也没有清除阶段的遍历开销,整体停顿时间极短(通常在毫秒级)
对象什么时候会离开新生代?
不是所有对象都永远待在新生代。V8 设有晋升机制:
- 一个对象若在 Scavenge 中经历过**两次回收仍存活**,就会被移到老生代
- 大对象(如超过 1MB 的数组或字符串)会直接分配到老生代,跳过新生代
- To 空间剩余容量不足时,也会触发提前晋升,避免复制失败
Scavenge 的局限与配合策略
它高效但有代价:可用内存始终只有新生代总容量的一半;且无法处理跨代引用(比如老生代对象引用了新生代对象)。为此 V8 引入了写屏障(Write Barrier)机制:
- 当老生代对象新增对新生代对象的引用时,V8 会记录这个“跨代指针”到记忆集(Remembered Set)
- 这样下次老生代 GC 时,就能把记忆集里的新生代对象也当作根来扫描,防止误回收
- Scavenge 本身不处理这类引用,依赖写屏障保障正确性
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










