内存泄漏与垃圾回收机制

引用借鉴

一、垃圾回收机制–标记清除

算法步骤:
1、垃圾回收器创建了一个“roots"列表。roots通常是代码中全局变量的引用。JS中,”window“对象是一个全局变量,被当作root。window对象总是存在,因此垃圾回收器可以检查它和它所有的子对象是否存在(即不是垃圾)
2、所有的roots被检查和标记为激活(即不是垃圾)。所有的子对象也被递归地检查。从root开始的所有对象如果是可达的,它就不被当作垃圾.
3、所有未被标记的内存都会被当作垃圾,收集器现在可以释放内存,归还给操作系统了

二、四种常见的内存变量

1、意外全局变量

没有声明(let,const,var)的变量 或者
function a() {
	 this.b = 1
}

//Foo调用自己,this指向全局对象,所以也成了全局变量
a()

解决办法:
使用严格模式来避免意外的全局变量,此时上例的this指向undefined。如果必须使用全局变量存储大量的数据的时,确保用完之后把它设置为null或者重新定义

2、被遗忘的定时器或者回调函数

现代的浏览器(包括 IE 和 Microsoft Edge)使用了更先进的垃圾回收算法(标记清除),已经可以正确检测和处理循环引用了

3、脱离DOM引用

如果把DOM 存成字典(JSON 键值对)或者数组,此时,同样的 DOM 元素存在两个引用:一个在 DOM 树中,另一个在字典中。那么将来需要把两个引用都清除,否则就会造成内存泄露

如果代码中保存了ul中一个li的引用,将来要删除整个ul的时候,我们会以为ul中的其他所有li都会被删掉,但是实际上,li是ul的子节点,子元素是父元素的引用关系,由于代码保留了li的引用,导致整个ul仍然待在内存中

4、闭包

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing)
      console.log("hi");
  };
    
  theThing = {
    longStr: new Array(1000000).join('*'),
    someMethod: function () {
      console.log(someMessage);
    }
  };
};

setInterval(replaceThing, 1000);

每次调用 replaceThing ,theThing 得到一个包含一个大数组和一个新闭包(someMethod)的新对象。同时,变量 unused 是一个引用 originalThing 的闭包(先前的 replaceThing 又调用了 theThing )。someMethod 可以通过 theThing 使用,someMethod 与 unused 分享闭包作用域,尽管 unused 从未使用,它引用的 originalThing 迫使它保留在内存中(防止被回收)。

解决:在 replaceThing 的最后添加 originalThing = null

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值