Garbage Collection
August 28, 2025
前言
- 什么是垃圾
- 怎么产生垃圾
- 为什么要垃圾回收
- 垃圾回收是怎样进行的
- V8引擎对垃圾回收进行了什么优化
什么是垃圾
在程序中占用着内存,且不被需要的变量(函数、变量、对象等)就是垃圾。
垃圾是怎么产生的
没有被引用。
为什么要垃圾回收
JS中的变量在不再需要后,变成垃圾后,会占着系统的内存,程序在运行中就会占用越来越多的内存,轻则影响系统性能,重则会导致程序崩溃。 所以对于持续运行的服务进程,必须要及时释放内存(垃圾回收)。
垃圾回收机制
JavaScript
垃圾回收机制的原理就是定期找出那些不再用到的内存(变量),然后释放其内存。(为什么不是实时的找出无用内存并释放呢?因为开销太大)。
那怎么找出所谓的垃圾呢?
- 标记清除算法
- 引用计数算法
标记清除算法
标记清除(Mark-Sweep
)此算法在JavaScript
里是最常用的,大多数的浏览器使用的都是此算法,不同的是不同浏览器对此算法都进行了加工优化。
此算法分为标记和清除两个步骤。
- 标记:为所有活动的对象做上标记。
- 清除:把没有标记的对象清除。
过程
- 垃圾收集器在运行时会给内存中的所有变量都加上一个标记,假设内存中的所有对象都是垃圾。全标记为
0
。(怎么做标记?)。 - 从各个根对象(根对象有什么?)开始遍历,把可以遍历到的节点改为
1
。 - 清理所有标记为
0
的垃圾。销毁并回收占用的内存。 - 开始第一步,等待下一轮垃圾回收。
优点
实现比较简单。
缺点
- 内存碎片化。在清除内存之后,剩余的内存位置是不变的,导致空闲的内存空间是不连续的,出现内存碎片。
- 分配速度慢。在分配新的内存时,都要遍历空闲的内存。
标记整理
这个是在标记清除算法的缺点(清除后剩余的对象位置不变而导致空闲内存不连续,从而导致内存分配问题)改进而来的。主要解决标记清除算法在清除垃圾后,存在不连续的内存空间问题。
此算法和标记清除算法的差不多,只是在标记结束后,标记整理算法会将活着的对象向内存的一端移动,然后再清理掉边界的内存。
引用计数算法
引用计数Reference Counting
,此算法的策略是跟踪记录每个变量值被使用的次数。当某个变量的被使用次数(引用计数)为0
,那么就会被垃圾回收机制回收。
已複製!let a = new Object(); // 此对象的引用计数为 1(a引用) let b = a; // 此对象的引用计数是 2(a,b引用) a = null // 此对象的引用计数为 1(b引用) b = null // 此对象的引用计数为 0(无引用 ... // GC 回收此对象
优点
在引用计数为0
时,也就是在变成垃圾的那一刻就会被回收,所以它可以立即回收垃圾。
而标记清除算法,则需要在每隔一段时间进行一次,此时引用程序就需要暂停去执行一段时间的GC
,此外标记清除需要遍历堆中的对象来清除。而引用计数只需要在引用时计数就可以。
缺点
- 需要一个计数器,这个计数器可能需要很大。(因为我们不知道被引用数量的上限)
- 无法解决循环引用无法回收的问题。
V8
对GC
的优化
...