常见的js内存泄漏

什么是内存泄露?

本质上,内存泄露可以定义为:应用程序不再需要占用内存的时候,由于某些原因,内存没有被操作系统或可用内存池回收。编程语言管理内存的方式各不相同。只有开发者最清楚哪些内存不需要了,操作系统可以回收。一些编程语言提供了语言特性,可以帮助开发者做此类事情。另一些则寄希望于开发者对内存是否需 要清晰明了。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>

const arr = [1, 2, 3, 4];
console.log('hello world');

如果增加一行代码,解除arr对[1, 2, 3, 4]引用,这块内存就可以被垃圾回收机制释放了。

let arr = [1, 2, 3, 4];
console.log('hello world');
arr = null;

上面代码中,arr重置为null,就解除了对[1, 2, 3, 4]的引用,引用次数变成了0,内存就可以释放出来了。

因此,并不是说有了垃圾回收机制,开发者就轻松了。你还是需要关注内存占用:那些很占空间的值,一旦不再用到,你必须检查是否还存在对它们的引用。
如果是的话,就必须手动解除引用。

常见的 JavaScript 内存泄露

1:意外的全局变量
JavaScript 处理未定义变量的方式比较宽松:未定义的变量会在全局对象创建一个新变量。

function foo(arg) {
    bar = "this is a hidden global variable";
}

真相是:
function foo(arg) {
    window.bar = "this is an explicit global variable";
}


另一种意外的全局变量可能由 this 创建:
function foo() {
    this.variable = "potential accidental global";
}
foo();

启用严格模式解析 JavaScript避免意外的全局变量。在 JavaScript 文件头部加上 'use strict',可以避免此类错误发生。

全局变量注意事项!!!
尽管我们讨论了一些意外的全局变量,但是仍有一些明确的全局变量产生的垃圾。它们被定义为不可回收(除非定义为空或重新分配)。
 临尤其当全局变量用于临时存储和处理大量信息时,需要多加小心。如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义。
 与全局变量相关的增加内存消耗的一个主因是缓存。缓存数据是为了重用,缓存必须有一个大小上限才有用。高内存消耗导致缓存突破上限,
 因为缓 存内容无法被回收。

2:被遗忘的计时器或回调函数
示例代码:
var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

所以:与节点或数据关联的计时器不再需要,node 对象可以删除,整个回调函数也不需要了。可是,计时器回调函数仍然没被回收(计时器停止才会被回收)。同时,someResource 如果存储了大量的数据,也是无法被回收的。所以先停止定时器 然后再回收


3:脱离 DOM 的引用
有时,保存 DOM 节点内部数据结构很有用。假如你想快速更新表格的几行内容,把每一行 DOM 存成JSON 键值对
或者数组。此时,同样的 DOM 元素存在两个引用,将来你决定删除这些行时,需要把两个引用都清除。
var elements = {
    button: document.getElementById('button'),
    image: document.getElementById('image'),
    text: document.getElementById('text')
};

function doStuff() {
    image.src = 'http://some.url/image';
    button.click();
    console.log(text.innerHTML);
    // 更多逻辑
}

function removeButton() {
    // 按钮是 body 的后代元素
    document.body.removeChild(document.getElementById('button'));
}
// 虽然我们用removeChild移除了button, 但是还在elements对象里保存着#button的引用,DOM元素还在内存里面.不能被垃圾回收站回收。

4:闭包
闭包实际上非常容易造成JavaScript对象和DOM对象的隐蔽循环引用。
代码示例:
function example(){
    var element =document.getElementByID("div1"); //①
    element.onclick = function() {
        alert("This is a leak!"); //②
    }
}
以上函数example() 中用匿名函数创建了一个闭包。
第①句: JS(element) ->DOM(div1)>
第②句: DOM(div1.onclick) ->JS(element)>
由此形成了JavaScript对象和DOM对象的隐蔽循环引用。
 2.解决方法:
常用的解决方法就是在JavaScript代码段运行完之时将形成循环引用的JavaScript对象手动设置为空,切断引用。
修改的例子如下:
[javascript] view plain copy print?
function example(){
    var element =document.getElementByID("div1"); //①
    element.onclick = function() {
        alert("This is a leak!"); //②
    }
    element = null; //添加的语句
}


</body>
</html>

转载于:https://my.oschina.net/shuaihong/blog/1548043

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值