垃圾回收机制
提问
- 简单介绍一下 垃圾回收
- 介绍一些标记清除法
- V8引擎的垃圾回收机制
垃圾回收
垃圾回收是一种自动内存管理机制。
当计算机上的动态内存不再需要时,就应该予以释放,让出内存。 (程勋是运行在内存里的,当声明一个变量,定义一个函数时,都会占用内存。内存的容量是有限的,对于不再使用的变量、函数等, 应该予以释放。)
垃圾回收方法:
- 引用计数法 (低版本IE采用的方法)
- 标记-清除法 (现代浏览器使用的方法)
标记清除法
标记清除法会 在 垃圾回收期、定期的从 全局对象window开始,找所有从这个对象开始引用的对象,再找这些对象引用的对象, 对这些活着的对象进行标记,这是标记阶段。
在清除阶段,清除那些没有被标记的对象。
V8引擎的垃圾回收机制
V8的垃圾回收策略基于分代回收机制,该机制又基于 世代假说。该假说有两个特点:
- 大部分新生代倾向于早死;
- 不死的对象,会活得更久。
基于这个理论,现代垃圾回收算法根据对象的存活时间将内存进行了分代,并对不同分代的内存采用不同的高效算法进行垃圾回收。
- 新生代:对象的存活时间较短。新生对象或只经过一次垃圾回收的对象。
- 老生代:对象的存活时间较长。经历过一次或多次垃圾回收的对象。
新生代被分为From
和 To
两个空间。 To
一般是闲置的。当From
空间满了的时候,就会执行Scavenge
算法进行 垃圾回收。当执行垃圾回收算法的时候应用逻辑就会停止,等垃圾回收结束后再继续执行。这个算法分为三步:
- 检查
From
空间的存活对象,如果对象存活则判断对象对象是否满足晋升到老生代的条件,如果满足条件则晋升到老生代。 如果不满足条件则移动To
空间。 - 如果对象不存活,则释放对象的空间。
- 最后将
From
空间和To
空间校色进行交换。
新生代对象晋升老生代有两个条件:
- 判断对象是否已经经过一次
Scavenge
回收。若经历过,则将对象从From
空间复制到老生代中; 若没有经历,则复制到To
空间; To
空间的内存使用占比是否超过限制。当对象从From
空间复制到To
空间时,若To
空间使用超过 25%, 则对象直接晋升到老生代中。设置25%的原因主要是因为算法结束后,两个空间结束后会交换位置, 如果To
空间的内存太小,会影响后续的内存分配。
老生代采用了标记清除法和标记压缩法。标记清除法首先会对内存中存活的对象进行标记,标记结束后清除掉哪些没有标记的对象。 由于标记清除后会造成很多内存碎片,不便于后面的内存分配。所以为了解决内存碎片的问题引入了标记压缩法。
由于在进行垃圾回收的时候会暂停应用的逻辑,对于新生代方法由于内存小,每次停顿的时间不会太长, 但对于老生代来说每次垃圾回收的时间长,停顿会造成很大的影响。 为了解决这个问题,V8引入了增量标记的方法,将一次停顿进行的过程分为了多步, 每次执行完一小步就让运行逻辑执行一会,就这样交替运行。