JS垃圾回收机制

目录

标记清除(mark and sweep)

大部分浏览器以此方式进行垃圾回收,当变量进入执行环境(函数中声明变量)的时候,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”,在离开环境之后还有的变量则是需要被删除的变量。标记方式不定,可以是某个特殊位的反转或维护一个列表等。

垃圾收集器给内存中的所有变量都加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记。在此之后再被加上的标记的变量即为需要回收的变量,因为环境中的变量已经无法访问到这些变量。

标记清除 (mark and sweep)流程

📌可达性:针对不可达的垃圾进行回收

标记清除具体gc回收流程:

  1. 遍历内存中所有的对象,对它们加一个tag,标记为0
  2. 对windows进行递归,找到可达的对象,标记改为1
  3. 销毁标记为0的垃圾
  4. 将内存里的对象重新标记为0,等待下一次的gc回收

标记清除的问题是什么?

mark and sweep 最大的问题在于一次垃圾回收后,内存空间中出现不连续的情况。这种内存碎片会对后面的内存分配造成问题,因为如果出现一个大对象,此时所有内存空间碎片无法完成分配,就会存在内存适配的困扰。


如何解决 mark and sweep 的问题? 新回收策略mark-compact 提出来了

mark-compact 标记整理,在mark sweep的基础上,活着的对象往一端移动,移动完成后,再经理掉边界外的内存

引用计数(reference counting)

这种方式常常会引起内存泄漏,低版本的IE使用这种方式。机制就是跟踪一个值的引用次数,当声明一个变量并将一个引用类型赋值给该变量时该值引用次数加1,当这个变量指向其他一个时该值的引用次数便减一。当该值引用次数为0时就会被回收。

引用计数有什么问题,为什么后面都不用了?

  1. 循环引用内存就会出现泄漏,无法解决循环引用的问题
  2. 计数器也是要占用内存的
1
2
3
4
5
6
function test(){
let A = new Object();
let B = new Object();
A.b = B
B.a = A
}

个人理解

  1. 为什么闭包会导致内存泄漏?

    如果执行环境内的变量被全局变量引用,该变量在内存中则无法释放,因为和全局变量有关联。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    function test(){
    var a = 1; //初始化添加标记
    return function(){
    a++
    console.log(a)
    }
    }
    var b = test();
    b();//2
    b();//3

JS垃圾回收机制
http://arch94.github.io/2023/08/24/JS垃圾回收机制/
作者
Arch Sun
发布于
2023年8月24日
许可协议