V8中的垃圾回收器与内存管理
最近在正好看到垃圾回收相关的东西,所以借此写一篇记录一下以加深印象
v8内存管理
v8虚拟机的内存,64位系统限制大小1.4GB,32位系统0.7GB。
js中的引用类型都是存放在堆内存中
栈
栈内存,小且连续存储,系统自动分配,自动回收
堆
大且不连续
代际假说
垃圾回收中的术语:代际假说
特点:
- 大部分对象在内存中存在时间很短,比如函数内的变量,块级作用域中的变量,函数或者代码块执行结束,作用域定义的变量就会被销毁。很多对象一旦分配内存,很快就变得不可访问
- 不死的对象,会活得更久,比如window,DOM,Web API
垃圾回收
v8垃圾回收算法主要是分代式垃圾回收机制
首先V8将堆内存分为新生代和老生代区域,新生代又被划分为对象区( from space )和空闲区( to space ),这两个区域同一时间只有一个在工作
新生代 (new space)与老生代 (old space)
基于代际假说,会把堆内存分为新生代与老生代
1.在V8中,会把堆内存分为新生代和老生代两个区域,新生代存放的是生存时间短的对象,老生代存放生存时间久的对象
2.新生代64位系统支持16MB内存,32位为8MB内存的,老生代容量会大很多
3.主垃圾回收器负责老生代垃圾回收,副垃圾回收器负责新生代垃圾回收
4.在node中,可以通过命令扩充内存,但是只能在启动时指定,无法在运行时自动扩充
副垃圾回收器
副垃圾回收器负责新生代垃圾回收。
Scavenge算法(新生代回收算法)
Scavenge算法基于cheney算法。
Scavenge算法是通过复制的方式实现垃圾回收。新生代空间被划分为两个区域,一般是对象区域,一半是空闲区域,这是由Scavenge算法决定的,这是他的缺点,只能使用堆内存中的一般,牺牲空间换取时间

1.新加入的对象都会存放到对象( from space )区域,对象区域快被写满时候,执行一次垃圾清理
2.垃圾回收时候,先检查对象( from space )区存活对象,将存活对象复制到空闲区(to space),非存活对象占用空间会被释放。复制完成,两个区域角色互换
3.简而言之,就是将存活对象从对象区复制到空闲区,回收未存活对象,然后角色互换(又叫翻转)

晋升
一个对象多次复制之后仍然存活,会被认为是生命周期比较长的对象,将此对象移动到老生代中,采用新的算法管理。这个过程叫做晋升
晋升条件:
1.经历过Scavenge回收
2.对象区空间内存占用比超过限制
从对象区复制到空闲区,先检查内存地址判断是否被Scavenge回收,已经经历,会将该对象从对象区(from space)复制到老生代空间,没有的话,复制到空闲区(to space)
或者
从对象区复制到空闲区时候,空闲区空间使用超过25%,对象也会直接晋升到老生代空间
主垃圾回收器与标记清除(Mark-Sweep老生代回收算法)
标记清除分为两个阶段,标记,清除
标记阶段遍历老生代中所有对象,标记活着的对象,清除阶段会清除掉没被标记的对象。
这种方法的问题在于,清除过后会出现不连续的内存碎片,所以有了标记整理(Mark-Compact)

标记整理(Mark-Compact)
标记对象死亡之后,将活着的对象向一端移动,移动完成直接清理掉最右边

全停顿(stop-the-world)
v8新生代执行一次垃圾回收需要50ms,老生代非增量式至少需要1s。
防止javascript应用逻辑和垃圾回收器看到的不一样,Scavenge,Mark-Sweep,Mark-Compact这几种算法都需要将应用逻辑暂停下来,垃圾回收完成在恢复执行应用逻辑。
v8老生代内存较大,存活对象多,全堆垃圾回收(full)会造成严重的问题,所以v8采用增量标记
参考资料:
本文标题:V8中的垃圾回收器与内存管理
文章作者:Niuhk
发布时间:2021-06-10
最后更新:2022-01-23
原始链接:https://www.niuhk.cn/2021/06/10/V8中的垃圾回收器与内存管理/
版权声明:转载请注明出处!
分享