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查看。
- 从引用计数的角度,理解闭包的内存泄漏,并且结合作用域链思考。
也就是引用计数是基于作用域链的概念的
老生代垃圾回收
- 老生代垃圾回收方法: 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