V8的堆内存的垃圾回收算法主要基于分代式垃圾回收机制 (Generational Collection)实现,该机制将内存空间划分为新生代和老生代内存空间,对不同空间采用不同的方式实现垃圾回收。
新生代内存空间的垃圾回收
新生代内存空间使用Scavenger 算法进行垃圾回收,是复制算法的一种变体,此方法会将新生代内存平均分配为两个内存空间(两个semi-space),分别为from和to空间,在内存到达一定阈值时会自动启用垃圾回收,工作流程如下。
复制算法(Scavenger)
- 标记 - 将所有的存活对象标记,确定哪些对象需要保留
- 复制 - 将所有存活对象从from区复制到to区
- 释放 - 将from区和to区互换,重定位引用指针,并将from区域清空
新生代内存一般较小,中存活对象少,移动对象成本低,但是需要多占用一倍的内存空间,采用scavenge算法更有优势,是一种以空间换时间的方式;
老生代内存空间的垃圾回收
老生代内存空间使用标记整理算法(Mark-Compact)和 标记清除(Mark-Sweep)进行垃圾回收,当内存使用达到一定阈值时,由V8引擎自动启动垃圾回收,根据需要自行选择垃圾回收的方式,工作流程如下。
标记清除算法(Mark-Sweep)
- 标记 - 将所有的存活对象标记,确定哪些对象需要保留
- 释放 - 清除所有未标记为引用的对象
老生代内存中,存活对象多,移动存活对象成本高,采用标记清除法只需要删除无用的对象即可,效率高,但是会产生碎片空间。
标记整理算法(Mark-Compact)
- 标记 - 将所有的存活对象标记,确定哪些对象需要保留
- 整理 - 将所有标记的对象移动到内存空间的一端,空出连续的内存空间
- 释放 - 将边界外空出的连续内存空间释放
标记整理算法解决了碎片空间问题,但是需要移动所有标记的对象,代价比较高,效率会比标记清除法低。
本文只是大概描述了几种垃圾回收算法,除此之外,V8对垃圾回收机制做了很多优化,如增量标记、增量清除、增量整理,惰性清除,惰性整理等,后续有时间会继续完善,大家也可以根据关键字自行搜索,感谢阅读。