← 返回目录

第 8 卷

第 8 / 10 卷日期:

  • 回收效率极致优化:新生代快速回收,老生代低频回收,平衡性能和内存占用;
  • 大幅减少STW时间,提升程序运行流畅度;
  • 适配绝大多数程序的内存使用规律(80%的对象存活时间短)。

缺点

  • 实现复杂,垃圾回收器逻辑量大;
  • 新生代复制算法有内存空间浪费(需预留空闲区域)。

应用语言

Java(HotSpot)、JavaScript(V8)、Go、C#(.NET)。

现代编程语言GC的核心特性

  1. 自动性:无需开发者手动干预,全流程自动完成;
  2. 透明性:开发者无需感知GC的执行过程,专注业务开发;
  3. 可控性:支持手动触发GC(如JS的 global.gc()、Java的 System.gc()),配置GC参数;
  4. 高效性:分代回收、并发回收、增量回收等优化,降低性能损耗;
  5. 安全性:避免内存越界、野指针、重复释放等问题。

主流编程语言的GC实现

  • JavaScript:V8引擎,分代回收(新生代Copying,老生代Mark-Sweep/Mark-Compact);
  • Java:HotSpot引擎,分代回收(新生代ParNew,老生代CMS/G1/ZGC);
  • Go:三色标记法+写屏障,并发回收,无分代,低STW;
  • Python:引用计数法+标记-清除法(解决循环引用)+分代回收;
  • C#:.NET CLR,分代回收+并发回收。
  1. V8引擎的垃圾回收机制具体是如何工作的?

V8引擎的核心背景

V8是谷歌开发的JS引擎,用于Chrome浏览器和Node.js,单线程执行,内存限制严格(32位系统约 1GB,64位系统约1.4GB),垃圾回收机制直接决定JS的运行性能,V8采用分代回收机制,将内存分

为新生代和老生代,针对不同代的对象采用不同的回收算法,兼顾回收效率和内存利用率。

V8内存布局(垃圾回收的基础)

V8将内存分为堆内存和栈内存,垃圾回收仅针对堆内存(栈内存由JS执行栈自动管理,函数执行完即

  1. 堆内存:存储引用数据类型(Object/Array/Function/RegExp),内存大、访问慢、需GC回收,

是垃圾回收的核心区域。

堆内存进一步分为新生代和老生代:

• 新生代(New Space):占堆内存的10% 左右,存储存活时间短的临时对象(如局部变量、临时

创建的对象),内存小(默认1-8MB),回收频率高、速度快;

• 老生代(Old Space):占堆内存的90% 左右,存储存活时间长的对象(如全局变量、常驻内存的

对象、新生代晋升的对象),内存大,回收频率低、速度慢。

V8垃圾回收的核心流程(分代回收)

  • 第一部分:新生代垃圾回收(Scavenge 算法,基于Copying复制算法)

新生代采用Scavenge算法,核心是空间换时间,将新生代内存分为两个大小相等的半区:From区(使用区)和To区(空闲区)。

回收步骤

  1. 内存分配:新创建的对象优先分配到From区,From区满时触发新生代GC;
  2. 标记存活对象:从根对象出发,扫描From区,标记可达的存活对象;
  3. 复制存活对象:将From区的存活对象复制到To区,并按内存地址连续排列,消除内存碎片;
  4. 清空From区:复制完成后,直接清空From区的所有内存,释放垃圾对象;
  5. 区交换:From区和To区角色互换,原To区变为新的From区,原From区变为新的To区,等待下一

次GC。

新生代对象的晋升机制(晋升到老生代)

存活对象满足以下任一条件,会从新生代晋升到老生代:

  1. 存活次数达标:对象在新生代GC中存活超过2次(默认阈值,可配置),说明是长期存活对象;
  2. 存活次数达标:对象在新生代GC中存活超过2次(默认阈值,可配置),说明是长期存活对象;
  3. To区内存不足:复制存活对象到To区时,To区空间占用超过50%,直接晋升到老生代(避免To区

快速满溢)。

  • 第二部分:老生代垃圾回收(Mark-Sweep + Mark-Compact 算法)

老生代对象特点:数量多、内存大、存活时间长,若使用Scavenge算法,复制成本过高,因此V8采用标记-清除(Mark-Sweep)和标记-整理(Mark-Compact)结合的算法,核心是时间换空间。

  1. 清除阶段:扫描整个老生代内存,释放未被标记的垃圾对象的内存,将内存归还给操作系统。
  2. 标记-整理(Mark-Compact)阶段(解决内存碎片)

标记-清除后会产生大量内存碎片,当内存碎片过多,无法分配大对象时,触发标记-整理:

  1. 标记阶段:与标记-清除的标记阶段一致,标记存活对象;
  2. 整理阶段:将所有存活对象移动到内存的一端,按连续地址排列;
  3. 清除阶段:释放存活对象另一端的所有内存,彻底消除内存碎片。
  • 第三部分:V8 GC的优化策略(减少STW卡顿)

传统GC会触发STW(Stop The World),暂停JS执行,导致页面卡顿,V8通过以下优化减少卡顿:

  1. 并发标记(Concurrent Marking):标记阶段与JS执行并行,垃圾回收器后台扫描标记,不暂停

JS执行;

  1. 增量标记(Incremental Marking):将标记阶段拆分为多个小步骤,穿插在JS执行间隙进行,避

免长时间STW;

  1. 惰性清除(Lazy Sweeping):清除阶段不一次性清除所有垃圾,而是在JS需要分配内存时,按

需清除部分垃圾,减少单次STW时间;

  1. 写屏障(Write Barrier):并发标记时,若JS修改对象引用(如新增/删除引用),通过写屏障记

录变化,避免标记错误;

  1. 并行清理(Parallel Sweeping):清除阶段启用多线程并行清理垃圾,提升清理效率。
  • V8 GC的核心总结
  1. 分代回收:新生代Scavenge(复制),老生代Mark-Sweep+Mark-Compact(标记-清除/整

理);

  1. 优化核心:通过并发/增量标记、惰性清除,减少STW卡顿,平衡回收效率和用户体验;
  2. 晋升机制:新生代存活久、To区不足的对象晋升到老生代;
  3. 适用场景:适配JS单线程模型,针对短期临时对象和长期常驻对象分别优化。
  4. JavaScript哪些操作可能引起内存泄漏?如何避免?

一、内存泄漏的定义

内存泄漏是指程序中不再使用的内存无法被垃圾回收器(GC)回收,持续占用内存资源,导致内存占用率逐渐升高,进而引发程序运行变慢、页面卡顿,严重时会触发内存溢出(OOM),导致程序崩

全站分卷索引 · 10 卷
  1. 1第 1 卷
  2. 2第 2 卷
  3. 3第 3 卷
  4. 4第 4 卷
  5. 5第 5 卷
  6. 6第 6 卷
  7. 7第 7 卷
  8. 8第 8 卷
  9. 9第 9 卷
  10. 10第 10 卷