你我写的 js 都是垃圾
作用
为了性能,防止过多内存被占用而导致性能下降
垃圾回收方式
标记清除
-
标记阶段:从全局变量出发,遍历所有可到达的变量,将其标记为活动对象
-
清除阶段:遍历内存,清除所有未被标记的对象
标记-整理算法
老生代中的标记-整理算法是为了解决标记-清除算法可能产生的内存碎片问题。在标记-整理算法中,清除阶段不直接清除垃圾对象,而是让存活的对象向内存的一端移动,然后清理掉移动后端的所有垃圾对象。通过这种方式,内存中的存活对象被紧凑地排列在一起,减少了内存碎片的产生。
引用计数法
-
每个对象都有一个与之关联的引用计数。当对象被引用时,其引用计数增加;
-
当对象不再被引用时,其引用计数减少。当引用计数为0时,该对象就可以被释放。
然而,引用计数在处理循环引用时可能会导致内存泄漏,因为循环引用的对象的引用计数永远不会变为0。
分代垃圾回收
这是一种更高效的垃圾回收策略,根据对象的存活时间将内存分为不同的代(generation)。通常将内存分为年轻代(young generation)和老年代(old generation)。大部分对象在创建后很快就会变得不可访问,所以年轻代会经常进行垃圾回收,而老年代则相对较少。这种方式可以更快地回收大部分短期不用的对象。
增量垃圾回收
在增量垃圾回收中,垃圾回收器将整个垃圾回收过程分为多个小步骤,交替执行垃圾回收和程序代码。这样可以减少单次垃圾回收的暂停时间,使回收过程更平滑,减少对程序性能的影响。
垃圾回收策略
V8的垃圾回收策略主要是基于分代式垃圾回收机制,其根据对象的存活时间将内存的垃圾回收进行不同的分代,然后对不同的分代采用不同的垃圾回收算法。
为了更快进行垃圾回收,将堆划分成两个区域:新生代和老生代
新生代
新生代中分了两个区域,to 空间和 from 空间,主要工作流程如下。
- 假设有 ABC 三个变量占据了一部分空间
- 假设 A 不再被用到,A 被标记为可清除
- 将未被标记的元素移动到 To 空间
- 将 from 空间内的元素清除
- 交换空间,进行后续处理
当然,如果有些变量一直被引用,那么就需要携带这些变量进行处理。
所以为了解决上述问题,当某个元素经历过一次上述交换,或者 to 空间内存超过 25% 则会将元素放入老生代
老生代
在老生代中管理大量内存,如果继续使用上述算法则会浪费一半内存,所以使用之前提到的标记清除算法,具体过程就如上面所说的一样。
清除完毕,因为储存的位置可能是不连续的,利用率可能会下降,所以就需要用到标记整理算法。
由于js 是单线程的,如果上述流程执行时间过长可能会造成卡顿(全停顿)。所以使用增量垃圾回收
同时为了充分利用多核CPU的性能,也将引入并行标记和并行清理,进一步地减少垃圾回收对主线程的影响,为应用提升更多的性能。
参考: