Js 垃圾回收机制(笔记)

March 01, 2020

介绍

最近阅读了文章前端面试查漏补缺—(二) 垃圾回收机制,发现对这方面知识细节的欠缺,所以找了一些资料学习一番,记性不好所以记下一些笔记。

内存生命周期

  1. 内存分配:当我们申明变量、函数、对象,并执行的时候,系统会自动为他们分配内存
  2. 内存使用:即读写内存,也就是使用变量、函数等
  3. 内存回收:使用完毕,由垃圾回收机制自动回收不再使用的内存

垃圾回收机制策略

引用计数垃圾收集

这是最初级的垃圾收集算法。此算法把“对象是否不再需要”简化定义为“对象有没有其他对象引用到它”。如果没有引用指向该对象(零引用),对象将被垃圾回收机制回收。

当对象存在循环引用时,则无法被回收。

标记清除算法

这个算法把“对象是否不再需要”简化定义为“对象是否可以获得”。

限制: 那些无法从根对象查询到的对象都将被清除

增量标记

为了减少全停顿的时间,V8对标记进行了优化,将一次停顿进行的标记过程,分成了很多小步。每执行完一小步就让应用逻辑执行一会儿,这样交替多次后完成标记。

长时间的GC,会导致应用暂停和无响应,将会导致糟糕的用户体验。从2011年起,v8就将「全暂停」标记换成了增量标记。改进后的标记方式,最大停顿时间减少到原来的1/6。

https://www.jianshu.com/p/b8ed21e8a4fb

分代回收(Generation GC)

通过区分「临时」与「持久」对象,多回收「临时对象区」(新生代 young generation)而减少每次 GC 的耗时,少回收「持久对象区」(老生代 tenured generation)减少每次需遍历的对象,从而减少每次 GC 的耗时。

V8 的内存限制:

  • 64 位系统下约为 1.4GB
  • 32 位系统下约为 0.7GB。

对应到分代内存中,默认情况下。

  • 32 位系统新生代内存大小为 16MB,老生代内存大小为 700MB。
  • 64 位系统下,新生代内存大小为 32MB,老生代内存大小为 1.4GB。

当然,在 Node.js 中可以通过设置 max-old-space-sizemax-new-space-size 参数调高内存上限,但在内存回收方面又存在 GC 时间过长的问题。

因为 1.5GB 的垃圾回收堆内存,V8 需要花费 50 毫秒以上,做一次非增量式的垃圾回收甚至要 1 秒以上。这时垃圾回收中引起 Javascript 线程暂停执行的事件,服务器的请求将会被挂起。在这样的花销下,应用的性能和影响力都会直线下降,因此需要多进程多节点来解决。

Orinoco

Orinoco 是 V8 垃圾回收器项目的代号,它利用最新的和最好的垃圾回收技术来降低主线程挂起的时间, 比如:并行(parallel)垃圾回收,增量(incremental)垃圾回收和并发(concurrent)垃圾回收。

https://zhuanlan.zhihu.com/p/55917130

垃圾回收策略对比

  • 新生代使用 Scavenge 算法:Cheney 算法
  • 老生代使用 Mark-Sweep & Mark-Compact 算法

| 回收算法 | Mark-Sweep | Mark-Compact | Scavenge | | -------- | ---------- | ------------ | -------- | | 速度 | 中等 | 最慢 | 最快 | | 空间开销 | 少 | 少 | 双倍空间 | | 碎片 | 有碎片 | 无碎片 | 无碎片 |

参考