当前位置: 首页 > backend >正文

NodeJS中老生代和新生代和垃圾回收机制

Node.js 中的 老生代(Old Generation)新生代(New Generation),是指其运行的 V8 引擎内部管理 JavaScript 堆内存时使用的分代垃圾回收机制中的两个重要概念。理解这两代内存的作用,有助于深入理解 Node.js 的内存管理和垃圾回收行为。


1. 背景:什么是分代垃圾回收(Generational GC)

V8 引擎采用 分代垃圾回收策略,将堆内存分成不同的区域(代),主要基于“对象存活时间”的假设:

  • 绝大多数对象生命周期很短,马上就会被回收

  • 少数对象会存活较长时间

为了提升效率,V8 把堆分成两个主要区域:

  • 新生代(New Generation):用于存放新创建的对象

  • 老生代(Old Generation):用于存放存活时间较长的对象


2. 新生代(New Generation)

  • 也叫“年轻代”或“新生代堆

  • 内存较小,存储刚刚创建的对象

  • 新生代的垃圾回收称为 ScavengeMinor GC

  • GC 频率高,但耗时短

  • 对象如果在新生代经过一定次数的垃圾回收仍未被回收,就会被晋升到老生代

特点:

  • 小,回收快,频繁

  • 适合回收生命周期短的对象

  • 分为两个半区(From Space 和 To Space),复制算法实现回收


3. 老生代(Old Generation)

  • 又称“长生代”或“老生代堆”

  • 用来存放经过多次新生代 GC 后仍然存活的对象

  • 堆空间较大

  • 老生代的垃圾回收称为 Mark-SweepMark-Compact(Major GC)

  • GC 频率低,耗时相对长

  • 负责回收生命周期长的对象

特点:

  • 较大,回收较少,但耗时较长

  • 使用标记-清除和标记-整理算法进行回收

  • 老生代满了会触发全堆垃圾回收(Full GC),对性能影响较大


4. 简单类比

  • 新生代像是一个“缓冲区”,新来的对象先在这里呆着,经过几轮“考验”没被清理掉,就晋升到老生代。

  • 老生代则像是“持久区”,存放那些经过验证,存活时间长的对象。


5. Node.js 内存中的代际内存

Node.js 作为 V8 的宿主,内存管理同样遵循上述分代机制:

  • 当你的 Node.js 程序创建大量临时对象时,这些对象首先在新生代分配,频繁被垃圾回收释放。

  • 持久引用的对象(如全局变量、长时间保持的缓存对象)会被晋升到老生代。

  • 老生代内存增长过快,会导致较慢且影响性能的全堆垃圾回收。


6. 为什么分代GC对性能很重要?

  • 快速回收新生代,减少暂停时间,因为新生代的GC非常快,减少对程序执行的影响。

  • 减少对老生代的垃圾回收压力,通过合理晋升和回收策略,避免频繁耗时的全堆回收。


7. 你可以怎么用?

  • 可以通过启动参数调整堆大小和新生代大小,影响性能和内存占用:

node --max-old-space-size=2048 yourApp.js  # 最大老生代堆大小,单位MB
node --max-semi-space-size=16 yourApp.js  # 新生代空间大小,单位MB(不是所有版本都支持)
  • 通过 process.memoryUsage() 查看 heapUsedheapTotal,但要深入查看新生代和老生代大小,可以用 Chrome DevTools 或 v8 模块。


8. 总结

方面新生代 (New Generation)老生代 (Old Generation)
作用存放新创建的短命对象存放存活时间长的对象
大小
GC 类型Scavenge (Minor GC)Mark-Sweep/Mark-Compact (Major GC)
GC 频率
GC 耗时
性能影响


如果你想,我还能帮你讲讲 V8 的垃圾回收算法具体实现、如何诊断内存泄漏,以及调优技巧!需要吗?

二、Scavenge 和Mark-Sweep详细讲解

我们现在详细讲解一下 V8 引擎在 Node.js 中常用的两种垃圾回收算法:

  • Scavenge(清除式回收) —— 用于 新生代(New Generation)

  • Mark-Sweep(标记-清除) —— 用于 老生代(Old Generation)


一、Scavenge 算法(清除式 GC,用于新生代)

🔶 背景

新生代空间小,GC 频繁,因此需要一种 快速且高效 的垃圾回收算法。Scavenge 是一种基于 复制算法(Copying GC) 的实现,它将新生代内存划分为两块区域。

🔶 工作原理

新生代被划分为两个半区(semi-space):From SpaceTo Space

  1. 对象先被分配到 From Space。

  2. 当 GC 被触发时:

    • 扫描 From Space 中仍然“存活”的对象。

    • 把活着的对象 复制到 To Space

    • 然后清空 From Space。

  3. 完成后,From 和 To 的角色对调

          新生代 (New Gen)----------------------|   From   |   To    |----------------------|  活对象  |  空白   | --> 回收后 From、To 对调

🔶 晋升(Promotion)

当一个对象在新生代中 经历过多次 GC 仍然存活,或 To 空间不足以容纳它时,它就会被晋升到老生代

✅ 优点

  • 回收快,适合小对象。

  • 对短命对象非常高效。

❌ 缺点

  • 要使用 两倍空间

  • 不适合回收大量长生命周期对象。


二、Mark-Sweep 算法(标记-清除 GC,用于老生代)

🔷 背景

老生代内存大,对象生命周期长,不能频繁复制。适合使用更精细的垃圾回收算法。

🔷 工作原理

  1. Mark(标记阶段)

    • 遍历对象图,标记出仍然“可达”的对象(可通过 GC Root 找到)。

    • 这些可达对象被打上“存活”的标记。

  2. Sweep(清除阶段)

    • 扫描整个堆,回收那些未被标记的对象

    • 不会整理内存碎片。

        内存块:   [Obj1] [X] [Obj2] [X] [X] [Obj3]标记后:    ✓    ✗    ✓    ✗    ✗    ✓清除后:   [Obj1] [ ] [Obj2] [ ] [ ] [Obj3]

🔷 可能引发的问题

由于只清除内存,没有整理碎片,会造成内存碎片(fragmentation)


三、Mark-Compact(标记-整理)

为了解决 Mark-Sweep 带来的内存碎片问题,V8 在需要时使用 Mark-Compact(标记-压缩) 算法。

🧠 原理:

  • 先标记

  • 然后将所有存活对象往一边移动,整理出连续的空闲内存块

        清除前: [Obj1] [X] [Obj2] [X] [Obj3]压缩后: [Obj1] [Obj2] [Obj3] [ ] [ ]

❗ 这是耗时最高的回收方式(用于内存整理)。


四、对比总结

特性/算法Scavenge(复制)Mark-Sweep(老生代)Mark-Compact(整理)
应用区域新生代老生代老生代(内存碎片多时触发)
时间复杂度快速 O(n)较慢 O(n)最慢 O(n),带移动成本
内存碎片
空间需求高(需要双倍空间)
对象处理方式存活对象复制到另一块区域删除不可达对象删除不可达对象 + 整理存活对象


五、如何查看 Node.js 垃圾回收情况?

你可以通过下面的方式查看:

node --trace-gc app.js

输出示例:

[GC: scavenge 1.0 (1.2) -> 0.7 (1.0) MB, 0.2 ms]
[GC: mark-sweep 10.2 (20.0) -> 5.0 (10.0) MB, 12 ms]

六、结语

这两种算法配合使用,构成了 V8 引擎的高性能垃圾回收机制:

  • Scavenge 快速回收短命对象

  • Mark-Sweep / Mark-Compact 处理长生命周期对象

这样不仅节省资源,还保持执行效率。


如果你想,我还可以讲:

  • 如何用 Chrome DevTools 分析 Node.js 内存快照

  • Node.js 中的内存泄漏调试方式

  • --inspect 的 GC 监控技巧

是否继续深入?

http://www.xdnf.cn/news/14397.html

相关文章:

  • Arduino入门教程:6、计时与定时
  • 阿帕奇基金会软件授权与公司贡献者许可协议(中英双语版)
  • (笔记)1.web3学习-区块链技术
  • Web3-代币ERC20/ERC721以及合约安全溢出和下溢的研究
  • EXCEL破解VBA密码 ( 仅供学习研究使用)
  • [VSCode] VSCode 设置 python 的编译器
  • 40-Oracle 23 ai Bigfile~Smallfile-Basicfile~Securefile矩阵对比
  • NodeJS里经常用到require,require的模块加载机制是什么
  • lua版的Frpc
  • go.work
  • 车载通信架构 --- IP ECU 在连接被拒绝后的重连机制
  • Spring Cloud Gateway 全面学习指南
  • 论文略读:MLPs Learn In-Context on Regression and Classification Tasks
  • CM工作室发展史 下
  • Python装饰器:优雅增强函数行为的艺术
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月14日第108弹
  • Win10安装DockerDesktop踩坑记
  • Java学习_‘+’作连接符的情况
  • Go语言底层(五): 深入浅出Go语言的ants协程池
  • ASR语音转写技术全景解析:从原理到实战
  • shell三剑客
  • FileBrowser Quantum更丝滑的文件网盘共享FileBrowser的平替
  • Python命名空间与作用域:深入解析名称查找的艺术
  • halcon开发之我与阿莲的故事1
  • Web自动化测试详细流程和步骤
  • Vue框架详解与Element
  • Python Day51 学习(日志Day20复习)
  • Atcoder Beginner Contest 410 题解报告
  • 来自麻省理工和AI制药公司 Recursion 的结构与结合亲和力预测模型Boltz-2,解决小分子药物发现的关键问题
  • 高频计网面试题(附模板答案)