
在 JavaScript 中,GC 代表"垃圾回收"(Garbage Collection)。垃圾回收是一种自动内存管理机制,负责监测不再使用的对象,并释放它们占用的内存空间,以避免内存泄漏和资源浪费。
JavaScript 是一种高级编程语言,它在运行时动态地创建和销毁对象。当创建对象时,JavaScript 引擎会为其分配内存空间,而当对象不再被引用或使用时,内存空间应该被释放以便在后续的代码执行中重新利用。垃圾回收机制就是负责自动检测和清除不再需要的对象,以释放占用的内存。
用通俗的例子来解释的话就是:
假设内存空间是一间房间,里面满满当当都堆着各种各样的东西。这时候你想在房间里面再放新的东西,就要先把一些不要的旧东西清理出去。
JS 引擎就像个管家,它会定期查看房间里哪些东西不再被使用或者无法访问到了。这些被遗忘的旧物品就像是内存中的“垃圾”,会被 GC 收集起来扔出房间。扔出这些垃圾后,房间就空出空间来了,可以继续用来存放新的变量、对象等程序的数据了。
GC 就好比是程序的内存管家,不断地检查内存使用情况,发现那些可以被清理的垃圾,然后自动回收这些内存。这对保证 JS 程序平滑运行非常重要。
引用计数(Reference Counting)是 JS 中较早的垃圾回收方式之一。
✴️ 基本思想:
追踪记录每个对象被引用的次数,当一个对象的引用数达到 0 的时候,说明这个对象不再被使用,那么就可以将其占用的内存空间回收释放。每个对象有一个引用计数属性,初始值为 0 ==> 当对象被引用时,其计数器加 1 ==> 当引用失效时,计数器减 1 ==> 当计数器为 0 时,表示对象不再需要,该对象的内存空间可以被回收。
✅ 优点:
❌ 缺点:
由于以上问题,现代的 JavaScript 引擎通常不再采用纯粹的引用计数作为主要的垃圾回收机制。
标记清除(Mark and Sweep)是 JavaScript 中最常见的垃圾回收机制之一。它是一种用于自动内存管理的算法,用于检测和释放不再使用的对象,以避免内存泄漏和内存溢出。
✴️ 基本思想:
标记清除算法通过这两个阶段实现垃圾对象的回收。在标记阶段,垃圾回收器会确定哪些对象仍然处于活动状态。在清除阶段,垃圾回收器会清理所有未被标记的对象,释放内存空间。
✅ 优点:
❌ 缺点:
标记整理(Mark-and-Compact)是在基本标记清除算法基础上的改进。
✴️ 基本思想:
✅ 优点:
❌ 缺点: 存活对象移动需要额外时间与计算资源。标记整理对标记清除进行了改进和优化,应用更加广泛。
分代回收(Generational Garbage Collection)是 JS 垃圾回收机制中的重要优化,是现代 JavaScript 引擎中采用的一种高效垃圾回收策略,它可以显著提高应用的性能和内存管理效率
✴️ 基本思想:
将内存中的对象分为新生代和老生代,根据对象的生命周期不同进行不同策略的回收。在分代回收的策略中,新创建的对象首先分配到新生代。垃圾回收器在新生代执行频繁的小规模垃圾回收,通常采用快速而简单的算法(比如 Scavenge 算法)来清理不再使用的对象。当对象在新生代经历了一定次数的垃圾回收仍然存活时,它们将被晋升到老生代。老生代的垃圾回收较为复杂,可能会涉及更多的算法和更大的回收范围。
✅ 优点:
通过区分不同对象的生命周期,它可以更精确地选择垃圾回收的时机和策略。大多数对象在创建后很快就变得不可访问,因此将它们分配到新生代,并频繁进行小规模的垃圾回收,可以有效地释放短期存活对象的内存。而那些长期存活的对象,由于它们在老生代,可能需要较长时间才会进行垃圾回收,从而避免频繁地进行大规模回收,提高了性能。
❌ 缺点:
空闲时垃圾回收(Idle-time Garbage Collection)是 JS 垃圾回收机制的一种常见优化技术,用于在系统空闲或闲置时进行垃圾回收,以减少对应用性能的影响。这种技术旨在在用户不活跃或浏览器空闲时,利用系统资源进行垃圾回收,而不会对正在运行的应用产生明显的影响。
✴️ 基本思想:
✅ 优点:
❌ 缺点: 空闲时垃圾回收并不意味着永远不会有任何垃圾回收暂停。在某些情况下,垃圾回收器可能仍需要在运行时进行一些必要的回收操作。空闲时垃圾回收只是在合适的时机尽量减少对应用的影响。
垃圾回收是 JS 自动内存管理非常重要的一部分,可以自动回收不再需要的内存对象,防止内存泄漏。主要的垃圾回收算法包括标记清除,标记整理,引用计数等。现代浏览器一般 combine 多个算法来实现。为了优化效率,会使用分代回收适当区分新生和老生对象,以及闲时回收利用 CPU 空闲资源。垃圾回收会有一定的性能影响,我们应该编写高质量代码来配合,减少不必要的内存占用。
总的来说,垃圾回收机制使得 JS 开发人员不再需要关注内存控制这块复杂的工作。它极大地简化了 JS 的内存管理,使开发人员可以专注于业务代码的实现。这是 JS 作为一门优秀动态语言的重要支撑。