谈谈js中的内存泄漏

内存泄漏这个词似乎经常都能听到,但是什么是内存泄漏?内存泄漏又有些什么影响呢?本文我们就来探讨一下js中的内存泄漏。

首先,我们看一下什么是内存泄漏?内存泄漏说白了就是本该被回收的内存因为一些异常没有被回收掉,而一直存在于内存中占用内存, 虽然说js有垃圾自动回收机制,但是如果我们的代码写法不当,会让变量一直处于“进入环境”的状态,无法被正常回收。下面 我们看一下一些常见的内存泄漏案例:

1、对象直接赋值

var a = {
  name: 'test1',
  age: 1
};
var b = a;
a = {
  name: 'test2',
  age: 2
};

console.log(a); // {name: 'test2', age: 2}
console.log(b); // {name: 'test1', age: 1}

上面的代码中,我们首先声明了变量a并初始化a的值为一个对象,然后我们将a的值赋值给了变量b,然后又给了a一个新的值,按照对象引用的理解b应该等于新赋值的a,其实不然我们第一次声明a并赋值的时候系统为我们申请了一块儿内存并将地址指向了a,然后将a赋值给b,系统将指向a的内存地址同时指向了b,接着a重新赋值切断了之前赋值时a与指向的内存地址之间的联系,又重新申请了一块儿内存指向了a,而原来指向a的那块儿内存还是在内存中,所以b还是之前a的值。所以在编写代码的过程中应该尽量避免对对象变量直接赋值。

2、意外的全局变量

function test() {
  a = 'test';
}

这种写法就相当于

function test() {
  window.a = 'test';
}

本来test函数调用完毕后,函数内部变量占用的内存是会被回收的,但是由于注册的是一个全局变量,导致a变量所占用的内存不会被回收。为了防止这种错误的发生,我们可以在js代码头部位置加上'use strict';以严格模式来编写代码。

3、定时器 setInterval或者setTimeout在不需要的时候没有被clear,导致定时器的回调函数及其内部依赖的变量都不能被回收,造成内存泄漏,比如我们在react的componentDidMount中使用了定时器,那么在componentWillUnmount中一定要记得清除定时器,不然就会造成内存泄漏。清除的方式如下:

clearTimeout(t);
clearInterval(t);

其中t是设置定时器时存储的变量。

4、如果给DOM元素添加的属性是一个对象的引用

var obj = {}; 
document.querySelector('selector').property = obj; 

在页面卸载的时候一定要记得将添加的DOM元素属性的值置为null,好让内存被回收。

window.onunload = function() {
   document.querySelector('selector').property = null;
}

5、事件有绑定就应该有移除

比如在react中,如果我们在componentDidMount中监听了某个节点的某个事件

node.addEventListener('event', func, false);

那么在componentWillUnmount中一定要移除事件的监听

node.removeEventListener('event', func, false);

上面说了这么多,有些朋友可能会觉得,现在电脑配置都还不错,内存泄漏点也没啥事情,这个想法也没啥太大问题,些许的问题在电脑上确实没有太大的感知,但是如果是运行在手机上呢?微信小程序中呢?那么可能导致的结果就是我们辛辛苦苦开发的应用直接闪退,所以我觉得我们还是应该重视这些问题,一点点的内存占用也是占用了,当工程越来越庞大的时候,这些小问题就会被累积起来,然后拖垮我们的程序。

  • 支付宝二维码 支付宝
  • 微信二维码 微信
相关文章