浏览器垃圾回收机制
浏览器垃圾回收机制
GC是什么
GC: Garbage Collection
垃圾产生 && 回收
1 | let a = { name: '炼狱先生' } |
{ name: '炼狱先生' }
保存在堆内存中,当a被重新赋值数组[1,2,3]
,那么它的引用关系就没有了,即变成了垃圾。
栈内存所存的基础数据类型大小是固定的,有操作系统自动分配和释放的;堆内存所存数据大小不固定,系统无法自动释放,需要js引擎手动释放
常见的垃圾回收策略
常见的两种:标记清除和引用计数
标记清除
执行gc时,递归遍历所有的对象,对可达对象进行标记,不可达对象当成垃圾回收。
类似:
- 垃圾收集器在运行时给内存的所有变量加上一个标记,假设所有对象都是垃圾,全标记0;
- 然后从跟对象开始遍历,把不是垃圾的节点改成1;
- 结束后清理所有标记为0的垃圾,销毁回收他们锁占用的空间;
- 最后,把所有对象修改为0,等待下一轮垃圾回收
引用计数
就是判断一个对象的引用数,引用数为0就回收,大于0就不回收。
步骤:
- 当声明了一个变量并将一个引用对象赋值给该变量时,这个值的引用次数为1;
- 这个值又赋给另一个变量,那么引用次数加1;
- 该变量的值被其他值覆盖了,一个引用对象引用次数减1;
- 当这个值引用次数为0,说明没有被引用了,就被回收。
- 缺点:出现循环引用,导致引用一直存在。
V8的垃圾回收算法
分代回收
V8将堆分为两个空间,一个叫新生代,一个叫老生代,新生代存放小的、存活周期短的对象。它只有1-8M的容量;老生代存放大的、存活周期长的对象。
V8使用不同的垃圾回收器和不同的回收算法:
- 副垃圾回收器 + Scavenge算法:负责新生代
- 主垃圾回收器 + Mark-Sweep(标记清除) + Mark-Compact(标记整理):老生代
新生代
Scavange算法
Scavange算法将新生代堆分为两部分,分别叫from-space和to-space,新分配的对象被放入from-space,from-space占满时,gc就启动了,标记活动对象和非活动对象,复制from-space的活动对象到to-space并排序,清除from-space中的非活动对象,最后将from-space和to-space进行角色互换,以便下一次的回收。
新生代对象晋升到老生代对象的两种情况:
- 一个对象经过多次复制依然存活;
- 复制一个对象到to-space时,占用超过25%
老生代
老生代为什么不用Scavenge算法:
- 反复复制存活率高的对象,效率低;
- 老生代内存空间大,使用以空间换时间,空间非常浪费
Mark-Sweep(标记清理)
- 标记阶段:对老生代对象进行第一次扫描,对活动对象进行标记;
- 清理阶段:对老生代对象进行第二次扫描,清除未标记的对象,即非活动对象。
清除非活动对象后,留下了零零散散的空位。
Marck-Compact(标记整理)
即在标记清理结束后,把剩下的活动对象整理到内存的一侧,整理完成后,直接回收边界的内存。
全停顿问题
js是一个单线程,代码运行需要用到js引擎,垃圾回收也需要用到js引擎,冲突了怎么办?垃圾回收优先于代码执行,会先停止代码的运行,等到垃圾回收完毕,再执行js代码,这个过程被称为全停顿。
新生代空间小,配合算法停顿时间短;但老生代某些时候对象较多,停顿时间长,使得页面出现了卡顿现象。
增量标记
就是将一次GC标记的过程,分成了很多小步,执行一小步再执行应用逻辑,交替多次完成一轮GC标记
增量标记后,每次暂停后如何恢复标记?如果执行程序时标记的对象被修改了怎么处理?对应引入了三色标记法与写屏障法
三色标记法
三色标记法即使用两个标记位和一个标记工作表来实现标记。
最初所有对象都被标记白色,从一组根对象开始,将这组对象标记为灰色并推入标记工作表中,当回收器从工作表中弹出并访问他的引用对象时,自身由灰色转变为黑色,并将下一个引用对象转为灰色,直到没有可标记为灰色的对象了,那么剩下的所有白色都是无法到达的,即需要回收的。
写屏障法
写屏障:增量中修改引用。
如果在增量标记时,第一次对象被引用,而后代码执行时修改了他的引用,那么第二次增量时会将被引用的新对象强制由白色对象改为灰色,从而保证下一次会被正确标记,又叫强三色不变性。
惰性清理
增量标记完成后,接着就是清除阶段了。但如果当前可用内存足够让代码执行,gc就选择了延迟清理,或者只清理部分,让js代码先执行,这个优化叫做惰性清理。
并发回收
在执行javascript的过程中,由辅助线程在后台完成执行垃圾回收的操作。主线程和辅助线程同时进行。
并行回收
并行GC:主线程和辅助线程同时执行同样的GC工作,由辅助线程来分担主线程的GC工作。
V8当前的垃圾回收机制
- 2011年,V8应用增量标记机制;
- 2018年,Chrome64和Nodejs启动并发标记,同时添加并行技术。
这几种技术在垃圾回收时融合使用。