JS垃圾回收机制

一、简介

“垃圾回收”是将程序中不再使用的内存空间进行回收的通俗说法。

C++等于语言的回收机制是由程序员编写析构函数进行垃圾回收

java等语言中的回收机制是由系统完成,无需程序员考虑

而javascript的回收机制就属于由系统完成回收。而细分javascript的回收机制又有两种:标记清除法、引用计数法。其中标记清除法现是主流,而引用计数法是在低版本的IE浏览器中使用。

二、引用计数法

简而言之就是一个对象被引用几次,那么它的引用计数就是几。而javascript中的回收机制会实时扫描对象的引用计数是0时就回收此对象。

1
2
A ---------> B ---------> C
//例如对象A有一个属性指向B,而B也有一个属性指向C。即使当前作用域中只有对象A有效,但由于指针的关系所有3个对象都必须保留在内存中。当离开A的当前作用域时(例如代码执行到声明A的函数的末尾处),垃圾收集器就可以释放A占用的内存。此时,由于没有什么指向B,因此B可以释放,最后,C也可以释放。

但此方法会发生内存泄露的问题

内存泄漏

内存泄漏是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

若有如下引用关系

循环引用

B引用了C,C引用了B,构成循环引用,则它们的引用计数最低为1,则不会被回收机制回收(尽管它们对于程序的运行无任何作用)。

当使用引用计数法垃圾回收机制时,若内存中存在两个或多个对象的引用链形成回路时,则此时发生循环引用,系统无法释放该内存,而导致内存泄漏,这是内存泄露的一种。

循环引用以及解决办法

闭包发生循环引用

例1

1
2
3
4
5
6
7
8
9
10
11
12
13
function outerfn(){
var obj = {
name: "张三"
}
function innerfn(){
return obj;
}
obj.objfn = innerfn;
return innerfn;
};
console.log(outerfn()());
//此情况中 innerfn函数引用了obj obj中也引用了innerfn 此时构成循环引用
//解决办法 去除obj.objfn = innerfn;

例2

1
2
3
4
5
6
7
8
9
10
11
12
13
function outerfn(){
var obj = {
name: "张三"
}
function innerfn(){
return 'in';
}
obj.objfn = innerfn;
return innerfn;
};
console.log(outerfn()());
//此情况中 innerfn函数虽未直接引用obj 但是却存在隐式引用 obj中引用了innerfn 此时构成循环引用
//解决办法 去除obj.objfn = innerfn;

DOM与JavaScript的循环引用

1
2
3
4
5
6
7
window.onload = function(){
var box = document.ElementById('box');
box.onclick = function(){
//打印box
console.log(box);
}
}
1
2
3
4
5
6
7
8
9
//此情况中 onclick函数引用了box(打印box)  box引用了onclick(box.onclick)  此时构成循环引用
//解决办法 将内部函数的声明写在外部函数的外面
window.onload = function(){
var box = document.ElementById('box');
box.onclick = doOnclick;
}
function doOnclick(){
console.log(this);
}

引用计数法的内存泄漏问题严重(已被大量浏览器抛弃使用),所以有了标记清除发来解决这一问题。

三、标记清除法

介绍

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

标记清除算法由以下步骤组成:
1.垃圾回收器构建”roots”列表。Roots通常是代码中保留引用的全局变量。在JavaScript中,”window”对象可以作为 root 全局变量示例。
2.所有的”roots”被检查并标记为active(即不是垃圾)。所有的children也被递归检查。从”root”能够到达的一切都不被认为是垃圾。
3.所有为不被标记为active的内存可以被认为是垃圾了。收集器限制可以释放这些内存并将其返回到操作系统

PS:类似与数据结构中图的深度优先遍历形成一个连通图。而不在连通图中的节点就会被释放。

标记清除法

最后更新: 2019年09月27日 10:23

原始链接: https://HowlCN1997.github.io/2019/05/12/简述JS垃圾回收机制/

× 请我吃糖~
打赏二维码