前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Javascript的内存泄漏分析

Javascript的内存泄漏分析

作者头像
sam dragon
发布2018-08-02 15:49:09
1.2K0
发布2018-08-02 15:49:09
举报
文章被收录于专栏:cnblogscnblogs

     作为程序员(更高大尚的称谓:研软件研发)的我们,无论是用Javascript,还是.net, java语言,肯定都遇到过内存泄漏的问题。只不过他们都有GC机制来帮助程序员完成内存回收的事情,如果你是C++开发者(你懂的)。。。。。,如果你是前端开发者,肯定在使用Javascript(你或者会说,Js是世界上最棒的语言),但我这里也得告诉你,Js的内存泄漏会来得更为突然,或者让你都无法察觉。本文就带大家领略一下Js的风骚:

一、模块化引起的内存泄漏

代码如下:

代码语言:javascript
复制
// module date.js
let date = null;
export default {
    init () {
        date = new Date();
    }
}

// main.js
import date from 'date.js';
date.init();

      上述是我们在现代前端工程方案中常见的代码格式,写一个模块,然后导出这一个模块。这里你应该知道date.js中的date是静态的(也就是你在N处导入date.js这个模块),但他们的date这个变量是共享的,一处改变,其他地方也对应发生变化。

二、假OOP范式引起的内存泄漏

在这里我为什么叫他假OOP呢,原因是这代码是想实现OOP范式却让自己掉到坑里去了,先上代码:

代码语言:javascript
复制
var fun = function(arg){
    this.sarg = arg; 
    var self = this;
    return function(){
        console.log(self.sarg);
    }
}
var fn = new fun('data arg');
fn();

首先,定义fun这个函数变量,然后返回一个function(这可以说就是典型的闭包)。闭包函数内引用外面的this对象(var self = this)。

然后,通过new的方式调用fun,返回值用fn接受,这里谁都知道返回的是一个函数,所以可以括号运算符进行执行。

2.1 利用chrome的memory面板进行分析

      定位到memory面板,然后刷新页面,再单击下图中所示的 'collect garbage'图标(也就是像回收站的图标),强制进行一次gc的回收,这样可以确保我们分析的对象就是可以存在内存泄漏的对象(至少他们是gc不可回收的对象)。

此图是上述代码片段在chrome浏览器中执行完成后,不能被gc回收的内存变量。

2.2 我认为的原因

先贴出发生内存泄漏的代码

代码语言:javascript
复制
var fun = function(arg){
    this.sarg = arg; //内存泄漏
    var self = this;//内存泄漏
    return function(){
        console.log(self.sarg);//内存泄漏
    }
}
var fn = new fun('data arg'); //内存泄漏
fn();

我认为的原因有以下几点:

1. 使用new运算符,他会创建一个对象,然后执行构造函数,并将构造函数对应的prototype(也就是原型)复制到新的对象上。

2. 上述new出来的新对象,在执行构造函数时,其this就指向了这个new出来的新对象

3. 然后上述代码在构造函数中又返回了一个函数,且函数中引用了new出来的新对象,返回函数赋值给了fn变量

4. 最的执行fn变量,正确输出我们想要的内容,这样程序就跑了(可以,我们new出来的新对象,没有人管也了,所以他就泄漏了)。

2.3 总结:

因为正常情况下,我们对一个function进行new操作的时候,在构造函数内是不会进行返回的,其实这个时候new操作默认给你返回的就是构造函数中的this对象。上述代码不建议出现在项目代码中,这是典型的错误写法,并示例只是为了演示泄漏。

三、DOM事件引起的内存泄漏

如果你是Jquery的忠粉,这部分可能对你有帮助,先上代码:

代码语言:javascript
复制
//html:
<input type="file" id="file" />
<button type="button" onclick="remove()" >but</button>

//js:
var file = document.getElementById("file");
file.addEventListener('change',function(event){
    console.log(event.target.value);
});
function remove(){
    file.remove();
}

首先我们在html中写两个标签,一个是file、一个是button;然后在js中对file标签绑定了change事件,然后对button绑定一个remove方法,用于移除file标签。

3.1 内存泄漏分析

在我们执行了remove方法后,然后收集内存分析:

     我们还按照示例二相同的操作,打开memory面板,然后执行一次GC回收后收集内存数据,然后查看Detached Dom tree(这就表示与DOM树失去联系的对象),然后我们把鼠标移动到native上,就会显示内存泄漏的代码位置。

Jquery忠粉们可以注意了,无论你是用的bind还是on进行事件的绑定,如果你在移除这些DOM元素前,没有进行相应的unbind或是off操作,那么恭喜你,内存一定泄漏了。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-07-08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、模块化引起的内存泄漏
  • 二、假OOP范式引起的内存泄漏
    • 2.1 利用chrome的memory面板进行分析
      • 2.2 我认为的原因
        • 2.3 总结:
        • 三、DOM事件引起的内存泄漏
          • 3.1 内存泄漏分析
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档