玖叶教程网

前端编程开发入门

浅谈 JS 内存泄漏问题

什么是内存泄漏?

程序的运行需要内存。只要程序提出要求,操作系统或者运行时(runtime)就必须供给内存。

对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能:变慢,延迟大等 ,重则导致进程崩溃。

我自己是一名从事了多年开发的web前端老程序员,目前辞职在做自己的web前端私人定制课程,今年年初我花了一个月整理了一份最适合2019年学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以关注我的头条号并在后台私信我:前端,即可免费获取。

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)。

内存泄漏的识别方法

1、使用快捷键 F12 或者 Ctrl+Shift+J 打开 Chrome 浏览器的「开发者工具」。

2、选择 Performance(老版为Timeline) 选项卡,在 Capture 选项中,只勾选 Memory。

3、设置完成后,点击最左边的 Record 按钮,然后就可以访问网页了。

4、打开一个网站,例如:www.taobao.com,当网页加载完成后,点击 Stop,等待分析结果。

5、然后在 ChartView 上寻找内存急速下降的部分,查看对应的 EventLog,可以从中找到 GC 的日志。

具体过程如下图所示:

内存泄露的常见原因及处理方式

常见原因:

1. 意外的全局变量

下面代码中变量bar在foo函数内,但是bar并没有声明.JS就会默认将它变为全局变量,这样在页面关闭之前都不会被释放.

function foo(){ bar=2 console.log('bar没有被声明!')}

b 没被声明,会变成一个全局变量,在页面关闭之前不会被释放.使用严格模式可以避免.

2. dom清空时,还存在引用

很多时候,为了方便存取,经常会将 DOM 结点暂时存储到数据结构中.但是在不需要该DOM节点时,忘记解除对它的引用,则会造成内存泄露.

var element = { shotCat: document.getElementById('shotCat')};document.body.removeChild(document.getElementById('shotCat'));// 如果element没有被回收,这里移除了 shotCat 节点也是没用的

与此类似情景还有: DOM 节点绑定了事件, 但是在移除的时候没有解除事件绑定,那么仅仅移除 DOM 节点也是没用的

3. 定时器中的内存泄漏

var someResource = getData();setInterval(function() { var node = document.getElementById('Node'); if(node) { node.innerHTML = JSON.stringify(someResource)); }}, 1000);

如果没有清除定时器,那么 someResource 就不会被释放,如果刚好它又占用了较大内存,就会引发性能问题. 但是 setTimeout ,它计时结束后它的回调里面引用的对象占用的内存是可以被回收的. 当然有些场景 setTimeout 的计时可能很长, 这样的情况下也是需要纳入考虑的.

4. 不规范地使用闭包

例如下面的例子: 相互循环引用.这是经常容易犯的错误,并且有时也不容易发现.

function foo() { var a = {}; function bar() { console.log(a); }; a.fn = bar; return bar; };

bar和a形成了相互循环引用.可能有人说bar里不使用console.log(a)不就没有引用了吗就不会造成内存泄露了.NONONO,bar作为一个闭包,即使它内部什么都没有,foo中的所有变量都还是隐式地被 bar所引用。 即使bar内什么都没有还是造成了循环引用,那真正的解决办法就是,不要将a.fn = bar.

避免策略:

  1. 减少不必要的全局变量,或者生命周期较长的对象,及时对无用的数据进行垃圾回收(即赋值为null);
  2. 注意程序逻辑,避免“死循环”之类的 ;
  3. 避免创建过多的对象 原则:不用了的东西要记得及时归还。
  4. 减少层级过多的引用

原文链接:https://mp.weixin.qq.com/s/umlEgXrKNdtrgHh58Mliig
作者:小生方勤

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言