---
url: /interview-question/5vkp8w1l/index.md
---
::: tip 提问

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

:::

## 垃圾回收

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

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

垃圾回收方法：

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

## 标记清除法

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

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

## V8引擎的垃圾回收机制

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

* 大部分新生代倾向于早死；
* 不死的对象，会活得更久。

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

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

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

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

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

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

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

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