此页内容

约 1029 字大约 3 分钟

2022-04-16

提问

  1. 简单介绍一下 垃圾回收
  2. 介绍一些标记清除法
  3. V8引擎的垃圾回收机制

垃圾回收

垃圾回收是一种自动内存管理机制。

当计算机上的动态内存不再需要时,就应该予以释放,让出内存。 (程勋是运行在内存里的,当声明一个变量,定义一个函数时,都会占用内存。内存的容量是有限的,对于不再使用的变量、函数等, 应该予以释放。)

垃圾回收方法:

  1. 引用计数法 (低版本IE采用的方法)
  2. 标记-清除法 (现代浏览器使用的方法)

标记清除法

标记清除法会 在 垃圾回收期、定期的从 全局对象window开始,找所有从这个对象开始引用的对象,再找这些对象引用的对象, 对这些活着的对象进行标记,这是标记阶段。

在清除阶段,清除那些没有被标记的对象。

V8引擎的垃圾回收机制

V8的垃圾回收策略基于分代回收机制,该机制又基于 世代假说。该假说有两个特点:

  • 大部分新生代倾向于早死;
  • 不死的对象,会活得更久。

基于这个理论,现代垃圾回收算法根据对象的存活时间将内存进行了分代,并对不同分代的内存采用不同的高效算法进行垃圾回收。

  • 新生代:对象的存活时间较短。新生对象或只经过一次垃圾回收的对象。
  • 老生代:对象的存活时间较长。经历过一次或多次垃圾回收的对象。

新生代被分为FromTo 两个空间。 To一般是闲置的。当From 空间满了的时候,就会执行Scavenge算法进行 垃圾回收。当执行垃圾回收算法的时候应用逻辑就会停止,等垃圾回收结束后再继续执行。这个算法分为三步:

  1. 检查From 空间的存活对象,如果对象存活则判断对象对象是否满足晋升到老生代的条件,如果满足条件则晋升到老生代。 如果不满足条件则移动To空间。
  2. 如果对象不存活,则释放对象的空间。
  3. 最后将From空间和To空间校色进行交换。

新生代对象晋升老生代有两个条件:

  1. 判断对象是否已经经过一次 Scavenge回收。若经历过,则将对象从From空间复制到老生代中; 若没有经历,则复制到 To空间;
  2. To空间的内存使用占比是否超过限制。当对象从From空间复制到To空间时,若To空间使用超过 25%, 则对象直接晋升到老生代中。设置25%的原因主要是因为算法结束后,两个空间结束后会交换位置, 如果To空间的内存太小,会影响后续的内存分配。

老生代采用了标记清除法和标记压缩法。标记清除法首先会对内存中存活的对象进行标记,标记结束后清除掉哪些没有标记的对象。 由于标记清除后会造成很多内存碎片,不便于后面的内存分配。所以为了解决内存碎片的问题引入了标记压缩法。

由于在进行垃圾回收的时候会暂停应用的逻辑,对于新生代方法由于内存小,每次停顿的时间不会太长, 但对于老生代来说每次垃圾回收的时间长,停顿会造成很大的影响。 为了解决这个问题,V8引入了增量标记的方法,将一次停顿进行的过程分为了多步, 每次执行完一小步就让运行逻辑执行一会,就这样交替运行。