JavaScript垃圾回收

js垃圾回收

一什么是垃圾

从生活中的角度可知,垃圾,就是人们不再需要的东西。在js中也一样,垃圾就是不再需要的变量。js通过自动内存管理实现内存分配和闲置资源回收,基本思路就是确定哪个变量不会再被用到了,就释放它占用的内存。

全局变量
在全局作用域下声明的变量都不是垃圾,因为你有可能再次使用到
比如在全局作用域下 var m=3
可能一开始m变量不会被用到,但在写多行代码后用到m,这时m就存在被用到的可能性,所以在js中不会被当做垃圾回收
局部变量
例子 function fn(){
var b=2;
console.log(b);
}
当fn函数执行时,会创建b变量,栈(或堆)内存会分配空间以保存相应的值。如果fn多次执行,且每次的变量b都不会被回收的话,是不是会产生很多的变量b,这样明显是不合理的。
所以局部变量在函数执行完后变成垃圾会被回收
单引用
let a=1;
let a=null;
一开始变量a开辟的内存空间存放1 ,但当值为null时,空间就没有作用了,变成垃圾被回收
双引用
let fruit={
name:“apple”
};
let food = fruit;
在windows上定义一个对象fruit,具有name属性。之后定义一个food变量指向fruit的内存空间。
这时如果想清除这片开辟的内存空间,就必须把fruit和food两个变量都清除,垃圾才能被回收干净
环引用
function marry(man, woman) {
woman.husband = man;
man.wife = woman;

return {
father: man,
mother: woman
}
}

let family = marry({
name: “John”
}, {
name: “Ann”
});
在这里插入图片描述

在一个family中,如果只去掉father和husband,此时name:“john”还存在,因为还存在wife可以引用john(即箭头指向)。
只有将所有指向该变量的对象清除才能够将该变量作为垃圾处理

二标记清理

标记清理是 js 中最常用的垃圾回收策略:当变量进入上下文,如在函数中声明一个变量时,这个变量会被加上存在于上下文中的标记。当变量离开上下文时,也会被加上离开上下文的标记。
垃圾回收程序运行:

  • 首先将内存中所有的变量标记好
  • 然后去掉 还在上下文中的变量 或者 被还在上下文中变量引用的变量 的标记,此时还有标记的就是要被删除的
  • 随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存

给变量加标记的方法有很多。比如,当变量进入上下文时,反转某一位;或者可以维护“在上下文中”和“不在上下文中”两个变量列表,可以把变量从一个列表转移到另一个列表。

三引用计数

这是一种没那么常用的垃圾回收策略,思路是对每个值都记录它被引用的次数,当引用次数为0时变量就会被垃圾回收程序清理。
let obj1 = {name: ‘张三’}; // 创建对象(称其为 a),给 obj1 赋值,则其引用次数为1
let obj2 = obj1; // a 的引用次数为 2

obj1 = null; // a 的引用次数为 1
obj2 = null; // a 的引用次数为 0,此时 a 就可以被垃圾回收了

声明一个变量并给它赋一个引用值时,引用数为1;如果同一个值又被赋给另一个变量,引用数加1;类似的,如果保存对该值引用的变量被其他值覆盖了,引用数减1

问题:循环引用
function f() {
let obj1 = {};
let obj2 = {};
obj1.a=obj2;
obj2.a=obj1;
}
此时obj1和obj2通过各自的a属性相互引用,两者引用数都是2,当f函数执行完毕后,在引用技术策略下obj1和obj2还存在,因为它们的引用数永远不会变成0
要解决这个问题,最好就是在不使用它们的时候将其设为 null

四前端垃圾回收的特殊性

对于前端而言,不仅有 js 进程,还有 DOM 进程。

(1)使用 remove 清除掉 dom 元素
(remove() 方法移除被选元素,包括所有文本和子节点)
let div=document.getElementById(‘root’);
div.οnclick=function(){};
div.remove();
console.log(div.onclick); //f(){}

可见onclick未被清除掉

(2)将其变为 null
let div=document.getElementById(‘root’);
let div2=document.getElementById(‘root’);
div.οnclick=function(){};
div=null;
console.log(div2.onclick);//f(){}

可见onclick也还未被清除掉。
但此时打印div.onclick会报错,因为此时div已经为null了

(3)同时使用 remove 和 null
let div=document.getElementById(‘root’);
let div2=document.getElementById(‘root’);
div.οnclick=function(){};
div=null;
div.remove();
console.log(div2.onclick);//null

可以看出这个 onclick 事件被清除掉了。所以对于前端而言,不仅要清除 js 进程,还要清除 dom 进程。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值