关于V8/MajorGC/MinorGC——性能优化

文章目录

概述 - 抓一条主线

  • V8 用"分代回收"来处理内存。
  • 核心思想是:大多数对象活不久,少数对象活很久。
  • 所以它把堆分成"新生代"和"老生代",分别用不同策略回收。

V8 里最重要的概念

新生代

  • 新创建出来的大多数对象先进入这里。
  • 特点:
    • 空间较小(这里的空间较小看最后的《空间较小》
    • 回收频繁
    • 回收速度优先
  • 这里主要对应 Minor GC。

老生代

  • 经历过几次回收还活着的对象,会被提升到这里。
  • 特点:
    • 空间更大
    • 对象活得更久
    • 回收更重、更慢
  • 这里主要对应 Major GC。

Minor GC

是什么

  • Minor GC 可以理解成"新生代垃圾回收"。
  • 它主要处理:
    • 刚创建出来的短命对象
    • 临时数组、临时对象、闭包上下文等

为什么它通常比较快

  • 因为 V8 假设:新生代里大部分对象很快就死掉
  • 所以 Minor GC 不需要全堆细查,只需要快速筛掉死对象,保留少数还活着的。

常见机制

  • V8 在新生代里常用的是一种复制式思路,常被叫做 Scavenge
  • 可以粗略理解为:
    • 新生代分成两块区域
    • 活着的对象复制到另一块
    • 死掉的对象直接整片丢弃
    • 两块区域角色互换
  • 这种方式适合"活对象少"的场景,所以很快。

触发时机

通常是:

  • 新生代空间满了
  • 分配新对象时发现放不下了

典型现象,如果代码里频繁创建大量短命对象,比如:

  • 每帧 {}
  • 每帧 []
  • 大量临时字符串
  • 高频 map/filter/reduce 产生中间对象

就会导致 Minor GC 很频繁。

Major GC

是什么

Major GC 可以理解成"老生代垃圾回收"。

它主要处理:

  • 老生代里的对象
  • 活得比较久的对象
  • 提升上去的缓存、长生命周期结构、闭包引用链等

为什么它更重

因为老生代里:

  • 对象更多
  • 引用关系更复杂
  • 活对象比例通常更高
    所以它不能像新生代那样简单复制一遍就完事,通常需要更复杂的算法。

常见机制

Major GC 往往涉及这些步骤中的一些:

  • Mark:标记哪些对象还活着
  • Sweep:清扫死对象
  • Compact:整理内存碎片,把活对象挪紧
    所以你会听到这些词:
  • Mark-Sweep
  • Mark-Compact

触发时机

一般是:

  • 老生代空间不足
  • 老生代碎片太多
  • 系统判断需要更深入回收

典型现象

如果代码里有很多:

  • 全局缓存
  • 长生命周期 Map/Object
  • 没释放的事件监听
  • 闭包一直引用大对象
  • 数组不断扩张又不清理
    就容易给老生代很大压力,导致 Major GC。

Minor GC 和 Major GC 的区别

最简单地记:

  • Minor GC:回收新生代,快,频繁
  • Major GC:回收老生代,重,较慢

再具体一点:

  • Minor GC 主要解决"短命垃圾"
  • Major GC 主要解决"长期存活后又变垃圾的对象"

对象为什么会进入老生代

通常有几种常见原因:

  • 熬过了几次 Minor GC:对象在新生代回收后还活着,就可能被提升。
  • 对象太大:某些大对象可能直接进入老生代。
  • 新生代放不下:有时也会提前晋升。

所以"进入老生代"不代表它永远重要,只代表它"活得比较久"或者"放不下"。

为什么 GC 会卡顿

因为垃圾回收不是完全免费。即使 V8 有很多优化,比如:

  • 增量标记
  • 并发标记
  • 并行回收

但某些阶段仍然可能需要 Stop-The-World,也就是:JS 执行暂停一下,让 GC 先干活。

所以你会感受到:

  • 掉帧
  • 卡顿
  • 尤其在动画、游戏、实时交互里更明显

Minor GC 卡顿特点

  • 单次通常短
  • 但如果太频繁,会形成很多小卡顿

Major GC 卡顿特点

  • 次数少一些
  • 但一次可能更明显、更重

在实际开发里怎么理解

可以把它想成两层保洁:

  • Minor GC(像"桌面清理"
    • 频率高
    • 清理临时纸屑
    • 动作快
  • Major GC(像"整个仓库大扫除"
    • 频率低
    • 但很费劲
    • 整理旧箱子、搬动东西、清碎片

和{}、[] 有什么关系

关系在于:

  • {}
  • 临时闭包
  • 临时字符串
  • 临时函数对象

这些如果大量高频创建,通常先增加的是 Minor GC 压力。

如果其中一些对象又被长期引用住了,就可能:

  • 晋升到老生代
  • 进一步增加 Major GC 压力

所以常见规律是:

  • 高频短命对象多 -> Minor GC 频繁
  • 长生命周期对象膨胀 -> Major GC 更重

常见误区

"GC 只和内存大小有关"

不对。还和这些强相关:

  • 对象创建频率
  • 对象生命周期
  • 引用结构复杂度
  • 是否碎片化

"Minor GC 一定没问题"

也不对。

  • 在游戏、动画、滚动、实时渲染里,很多次小停顿 一样会明显掉帧。

"只要少 new 就行"

不完全对。真正要看的是:

  • 是否在热路径里频繁创建
  • 是否造成对象逃逸和长生命周期引用
  • 是否产生大量中间对象

在前端/游戏里最该关注的点

每帧临时对象

比如:

  • 临时 {x, y}
  • 临时数组
  • 临时矩形、点、向量
  • 频繁字符串拼接

这类最容易造成 Minor GC 抖动。

长生命周期缓存

比如:

  • 资源缓存
  • 节点树引用
  • 事件监听没解绑
  • 大数组不清理

这类更容易推高 Major GC 压力。

闭包和回调链

比如:

  • 定时器持有上下文
  • Handler 未 recover
  • 监听器一直引用对象

这类容易让本该死掉的对象继续活着。

一个非常实用的判断方式

如果你看到问题是:

  • "偶尔非常卡一下" 更像 Major GC 或资源加载等重操作。

如果你看到问题是:

  • "持续轻微掉帧、抖动" 很可能有频繁 Minor GC。

当然这只是经验判断,不是绝对。

怎么减少 GC 压力

针对 Minor GC

  • 避免热路径里频繁创建临时对象
  • 复用 Rectangle、Point、数组、临时结构
  • 少造中间数组和中间对象

针对 Major GC

  • 清理不用的长生命周期引用
  • 解绑事件、清理定时器
  • 控制缓存大小
  • 避免对象被全局容器长期持有

一句话总结

  • V8 的 GC 核心是分代回收:
    • Minor GC:清理新生代,处理大量短命对象,快但可能很频繁
    • Major GC:清理老生代,处理长生命周期对象,更重,停顿可能更明显

《空间较小》- 新生代

是指:V8 为新生代预留的那块堆内存区域本身比较小(即系统/运行时提供给这类对象存放的内存区域大小较小)。

  • V8 把堆分成不同区域
  • 其中"新生代"这个区域整体容量相对老生代更小
  • 新创建对象通常先放进这个较小的区域里

可以这样理解

把 V8 堆想成两个仓库:

新生代

  • 小仓库
  • 放新来的东西
  • 周转很快

老生代

  • 大仓库
  • 放活得久的东西
  • 清理更麻烦

为什么要设计成"小空间"

因为 V8 的假设是:大多数新对象很快就会死掉,所以没必要一开始就给它们放进一个很大的区域。

放在小一点的新生代里有几个好处:

  • 回收更快
  • 扫描范围更小
  • GC 成本更低
  • 更适合高频处理短命对象

注意:对象本身也会影响分配

虽然"空间较小"指的是区域容量,不过你也可以顺带知道一个现实情况:

  • 某些特别大的对象,可能不会按普通小对象那样待在新生代里
  • 可能直接进别的区域,比如大对象区

所以并不是所有对象都老老实实先进新生代。

但对于一般普通对象,默认理解成"先进新生代"是对的。

相关推荐
蓝黑20204 小时前
Vue的 value=“1“ 和 :value=“1“ 有什么区别
前端·javascript·vue
小李子呢02114 小时前
前端八股6---v-model双向绑定
前端·javascript·算法
史迪仔01124 小时前
[QML] QML IMage图像处理
开发语言·前端·javascript·c++·qt
AI_Claude_code4 小时前
ZLibrary访问困境方案四:利用Cloudflare Workers等边缘计算实现访问
javascript·人工智能·爬虫·python·网络爬虫·边缘计算·爬山算法
Cobyte5 小时前
3.响应式系统基础:从发布订阅模式的角度理解 Vue2 的数据响应式原理
前端·javascript·vue.js
竹林8185 小时前
从零到一:在React前端中集成The Graph查询Uniswap V3池数据实战
前端·javascript
军军君016 小时前
Three.js基础功能学习十八:智能黑板实现实例五
前端·javascript·vue.js·3d·typescript·前端框架·threejs
Moment6 小时前
AI全栈入门指南:一文搞清楚NestJs 中的 Controller 和路由
前端·javascript·后端