原文链接:NodeJs internals: V8 & garbage collector
- 应用出现 heap out of memory 的时候
- 使用 --trace_gc 来追踪垃圾回收
- 使用 process.memoryUsage 查看 heapUsed, heapTotal
- v8-profiler
- node-heapdump
- node-memwatch
- Node.js(V8) 的 GC 机制
- 堆内存中分为 [[new-space][old-space]]
- 新生代内存空间:保存存活时间较短的对象
- 老生代内存空间:保存存活时间较长或常驻内存的对象
- Scavenge 算法:新生代对象的垃圾回收算法
- 采用复制的方式。
- 堆内存一分为二,两个部分成为 semisapce
- From空间:使用中的semispace
- To空间:闲置中的semispace
- 分配内存的时候,先从From空间中分配。
- 垃圾回收的时候,检查From空间的存活对象,复制这些存活对象到To空间,非存活对象的空间释放。
- 复制完成之后,From空间和To空间角色对换。
- 新生代中存活的对象会转移空间到老生代中,被称为晋升,条件为:
- 对象经历过一次 Scavenge 回收
- To 空间使用超过25%
- Mark-Sweep:老生代对象的垃圾回收算法
- 标记清除,分为两个阶段
- 标记阶段:遍历堆中的所有对象,标记活着的对象
- 清除阶段:清除未被标记的对象
- 每一次清除标记之后会产生内存空间不连续的情况,内存碎片。
- 如果需要分配内存给一个大的对象,就有可能导致所有的碎片空间都无法完成分配,而触发垃圾回收。
- 标记清除,分为两个阶段
- Mark-Compact:在Mark-Sweep基础上优化内存碎片问题
- 标记阶段结束后,把所有活着对象都往一端移动
- 移动完成之后直接清理掉另一边的所有内存
- Stop-the-world:GC需要暂停你的JavaScript执行代码来完成垃圾回收,V8的解决方案:
- Incremental-Marking:增量标记,把GC的一个需要长时间标记的任务分成多次来完成
- Lazy-Sweeping:懒清除,当前的空闲内存足以运行当前的代码的时候就先不清除
- Concurrent:V8利用多个线程(Worker)来同时进行标记清除
- Parallel:在JavaScript代码执行的时候,GC与其平行进行标记清除,以避免 Stop-the-world
- 堆内存中分为 [[new-space][old-space]]