V8垃圾回收机制入门
Node使用JavaScript在服务端操作大内存对象受到一定的限制(堆区),64位系统下约为1.4GB,栈区32位系统下是0.7GB,新生带64位是32M,32位是16M
node --max-new-space-size app.js
max-old-space-size app.js
读取大文件,上传服务器端,堆区内存会超出(2G的文件进行上传)
process.memoryUsage ->rss、heaptTotal、heapUsed
V8的垃圾回收策略主要基于分代式垃圾回收机制,在自动垃圾回收的演变过程中,人们发现没有一种垃圾回收算法能够胜任所有场景。V8中内存分为新生代和老生代两代。新生代为存活时间较短对象,老生代为存活时间较长的对象
固定的位置收拾、不能影响正在使用的、过一会收拾一次
目前V8采用了两个垃圾回收器,主垃圾回收器-Major GC(主要负责老生代的垃圾回收)和副垃圾回收器-minor GC(Scavenger 主要负责新生代的垃圾回收)V8之所以使用两个垃圾回收器,主要受到代际假说的影响
第一个是大部分对象都是朝生夕死的,形容有些变量存活的时间很短,第二是不死的对象,会活的更久,比如全局对象的window、DOM、WebAPI等对象
Scavebge算法
在分代的基础上,新声代的对象主要通过Scavenge算法进行垃圾回收,再具体实现时主要采用Cheney算法,Cheney算法是一种采用复制的方法实现的垃圾回收算法。它将内存一分为二,每一个空间称为semispace,这两个semispace中一个处于使用,一个处于闲置,处于使用的称为From。闲置的称为to,分配对象时先分配到form,当开始进行垃圾回收时,检查From存活对象复制到To,非存活被释放。然后互换位置,再次进行回收,发现被回收过直接晋升,或者发现To空间已经使用了额超过25%,他的缺点是只能使用堆内存的一半,这也是典型的空间换时间的办法,但是新生代申明周期短,恰恰就适合这个算法。

Mark-Sweep&mark-compact
V8老生带主要采用Mark-Sweep和Mark-compact,在使用Scavenge不适合,一个是对象较多需要赋值两太大,而且还是没能解决空间问题。Mark-Sweep是标记清除,标记那些死亡的对象,然后清除。但是清除过后会出现内存不连续的情况,所欲需要使用Mark-compact,它是基于Mark-Sweep演变而来的,它现将活着的对象移动到一边,移动完成后,直接清除边界外的内存。当CPU空间不足的时候会非常的高效,V8后续还引入了延迟处理,增量处理,并计划引入并行标记处理。
引用计数是计算机编程语言中的一直用内存管理计数,是指将资源(可以是对象、内存或者磁盘空间)的被引用次数保存起来,当被引用次数变为0的时候就将其释放的过程,使用引用计数计数可以实现自动资源管理的目的,同时引用计数还可以指使用引用计数计数回收未使用资源的垃圾回收算法。
V8垃圾回收机制
垃圾回收时通过GC Root(全局的window对象,位于每个ifrmae中,文档DOM树,存放栈上的变量)标记空间中活动对象和非活动对象,从GC Rots对象出发,遍历GC ROOT中的所有对象,能遍历到的对象,该对象是可访问的,那么必须保证这些对象应该在内存中保留,也称为可访问的对象为活动对象;通过GC Root没有遍历到的对象,则是不可访问的,那么这些不可访问的对象就可能被被回收,称为不可访问的对象为非活动对象。

主线程停下来进行GC叫全停顿(Stop-The-World)为了解决全停顿带来的卡顿,V8内部还有并行、并发、增量等垃圾回收技术。
并行回收在执行一个完整的垃圾回收过程中,垃圾回收器会使用多个辅助的线程来辅助执行垃圾回收。增量式垃圾回收,垃圾回收器将标记工作分解为更小的块,并且穿插在主线程不同人物之间执行,并发回收,回收线程在执行JavaScript的过程中,辅助线程能够在后太完成执行垃圾回收的操作
V8执行标记



三色标记法,V8提出三色标记法,黑色和白色,额外引入灰色,黑色表示这个节点被GC Root引用到了,而且该节点的子节点都已完成标记,白色表示这个节点没有被访问到,如果在本轮遍历结束时还是白色,那么这块数据就会被回收。
灰色表示这个节点被GC Root引用到,但子节点还没有被垃圾回收器标记处理,也表明目前正在处理这个节点;为什么会有灰色?window.a={};wndow.a.b = {};window.a.b.c={},扫描完一遍后window.a.b= {};导致b切开了,但是d确实限制,增量垃圾回收器添加了约束条件,不能让黑色节点指向白色节点,写屏障机制,写屏障机制会强制将被引用的白色节点编程灰色的,这样就保证了黑色节点不能指向宝色节点的约束条件,这个方法也被称为强三色不变性,因为在标记结束时所有的白色对象,对于垃圾回收器来说都是不可达到的,可以安全释放,在V8中,每次执行如window.a.b = value得写操作之后,V8会插入写屏障代码,强制将value这块内存标记为灰色。
常见的内存泄露问题
- 无限制增长的数组
- 无限制设置属性和值
- 任何模块内的私有变量和方法均是永驻内存的,可手动设置a=null进行内存释放。
- 大循环,无GC机会
内存泄露分析-node
node-inspector
console.log('Server PID', process.pid);
sudo node --inspect app.js
while true; do cur1 "http://localhost:1337/"; done
top -pic 2322