# 垃圾回收

V8的垃圾回收策略主要是基于`分代式垃圾回收机制`，其根据**对象的存活时间**将内存的垃圾回收进行不同的分代，然后对不同的分代采用不同的垃圾回收算法。

## **V8的内存结构**

在V8引擎的堆结构组成中，其实除了`新生代`和`老生代`外，还包含其他几个部分，但是垃圾回收的过程主要出现在新生代和老生代，所以对于其他的部分我们没必要做太多的深入，有兴趣的小伙伴儿可以查阅下相关资料，V8的内存结构主要由以下几个部分组成：

* `新生代(new_space)`：大多数的对象开始都会被分配在这里，这个区域相对较小但是垃圾回收特别频繁，该区域被分为两半，一半用来分配内存，另一半用于在垃圾回收时将需要保留的对象复制过来。
* `老生代(old_space)`：新生代中的对象在存活一段时间后就会被转移到老生代内存区，相对于新生代该内存区域的垃圾回收频率较低。老生代又分为`老生代指针区`和`老生代数据区`，前者包含大多数可能存在指向其他对象的指针的对象，后者只保存原始数据对象，这些对象没有指向其他对象的指针。
* `大对象区(large_object_space)`：存放体积超越其他区域大小的对象，每个对象都会有自己的内存，垃圾回收不会移动大对象区。
* `代码区(code_space)`：代码对象，会被分配在这里，唯一拥有执行权限的内存区域。
* `map区(map_space)`：存放Cell和Map，每个区域都是存放相同大小的元素，结构简单(这里没有做具体深入的了解，有清楚的小伙伴儿还麻烦解释下)。

![](/files/-LviyHoRtvghncn5O74u)

上图中的带斜纹的区域代表暂未使用的内存，新生代(new\_space)被划分为了两个部分，其中一部分叫做inactive new space，表示暂未激活的内存区域，另一部分为激活状态。

## 新生代回收

在V8引擎的内存结构中，新生代主要用于存放存活时间较短的对象。新生代内存是由两个`semispace(半空间)`构成的，内存最大值在`64`位系统和`32`位系统上分别为`32MB`和`16MB`，在新生代的垃圾回收过程中主要采用了`Scavenge`算法。

### 引用计数

引用计数主要是IE等旧浏览器在使用，通过计数器分析变量的引用次数，清除没有引用到的变量。对于存在循环引用的情况则无法处理。比如

```javascript
function cycle() {
    var o1 = {}
    var o2 = {}
    o1.a = o2
    o2.a = o1
}

cycle()
```

其中 o1 引用了 o2，o2 引用了 o1，在cycle函数执行完 o1，o2 都没有再次引用到，但是引用计数算法判断两者都存在引用。

### scavenge 算法

用于V8中的新生代内存，将新生代内存一分为二：From 和 To，在From 和 To 之间转换的过程完成垃圾回收。

![](/files/-M2HO9qIfzlGomUQTWTE)

## 老生代回收

在老生代中，因为管理着大量的存活对象，如果依旧使用`Scavenge`算法的话，很明显会浪费一半的内存，因此已经不再使用`Scavenge`算法，而是采用新的算法`Mark-Sweep(标记清除)`和`Mark-Compact(标记整理)`来进行管理。

{% hint style="info" %}
`引用计数`的算法，两个变量均存在指向自身的引用，因此依旧无法被回收，导致内存泄漏。

因此为了避免循环引用导致的内存泄漏问题，截至2012年所有的现代浏览器均放弃了这种算法，转而采用新的`Mark-Sweep(标记清除)`和`Mark-Compact(标记整理)`算法
{% endhint %}

### 标记清除

早期V8中堆内存采用的一种清除算法，全局扫描堆内存找出未使用到的对象进行标记并清除，由于未进行内存整理会存在内存碎片。

![](/files/-M2HQ59wH6nsm2I11rfq)

## 避免内存泄露

1. 尽可能少的创建全局变量
2. 手动清除定时器
3. 少用闭包
4. 清除DOM引用
5. 使用弱引用


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mm.ricky.moe/javascript/v8/la-ji-hui-shou.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
