深入探索V8垃圾回收机制

440

V8垃圾回收机制

基于分代(新生代、老生代)的垃圾回收,不同代的垃圾回收机制不同

javascript中的垃圾回收

  • 程序的运行需要内存,只要程序需要,操作系统就必须提供内存
  • javascript使用自动内存管理,即垃圾回收机制
  • 优点:简化开发、节省代码,因为自动就把垃圾回收了,不需代码操作
  • 缺点:像黑盒,开发人员很少能掌握内存分配与回收的具体过程

NodeJS中的内存管理

  • 网页端的内存泄漏,因为所有的页面都用着一套后端代码,而浏览器会有很多
  • 持续运行的服务进程node服务端程序,必须及时释放不再用的内存。后果: 轻则影响性能,重则导致进程崩溃

V8内存限制

因为内存越大,垃圾收集的时间越长。

  • 64位 》 1.4G内存 新生代32M(From to ) 老生代 1400M
  • 32位 》 0.7G内存 新生代16M (From to ) 老生代 700M

V8内存管理

  • JS对象是通过V8进行分配管理内存的
  • process.memoryUsage返回Node进程的内存占用量
res(所有的内存占用)、heapTotal、heapUsed、exteral(C++对象占用的内存)
  • 打开限制内存

node -max-new-space-size(16M KB) node -max-old-space-size(1G MB)

新生代垃圾回收

垃圾回收中的新生代和老生代是说的堆内存

from to

  • 空间小,存活对象少
  • 新生代又分为两个区域: From To,一个使用一个空闲
  • 检查from区域的存活对象,如果还活着就拷贝到To区域,然后from与to互换位置
  • 扫描策略为广度优先:在to区域会有两个指针(扫描指针、分配指针)
  • 当一个新生代中的对象经过多次回收还存活的话,生命周期比较长的对象被移动到老生代。比如:经过5次以上的回收还存在;TO空间使用占比超过25%;超大对象。

问: golbal.xxx = { name: 'tom' } 什么时候被回收呢?

引用计数

  • 语言引擎有一张引用表,保存内存中所有资源的引用次数。
  • 一个值引用次数 === 0,该内存会被释放

如何查看一个资源的引用次数呢?

通过浏览器的memory snapshot查看。

  • 从引用计数的角度,理解闭包的内存泄漏,并且结合作用域链思考。

也就是引用计数是基于作用域链的概念的

image.png

老生代垃圾回收

  • 老生代垃圾回收方法: mark-sweep(标记清除)、mark-compact(标记清理);
  • 老生代空间大,大部分都是活这的对象(因为只有活着的对象才会从新生代的to区域被转移到老生代),GC耗时比较长;
  • 在GC期间无法响应,STOP-THE-WORLD
  • V8有优化方案:进行增量处理,把大的暂停(STOP-THE-WORLD)换成小的暂停(INCREMETN-GC)increment-gc

mark-compact类似于电脑的碎片优化,进行左移动。

  • 两种清理方式mark-sweep/mark-compact都会存在,使用频率由浏览器决定。
  • V8主要是用mark-sweep,空间不足的时候用mark-compact