内存泄露
不再用到的内存,没有及时释放,就叫做内存泄漏。
对于持续运行的服务进程(daemon),必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃
JavaScript 的垃圾收集机制
javascript具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中的使用的内存。
JavaScript中最常用的垃圾收集方式是标记清除(mark-and-sweep)。当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其 标记为“离开环境”。
常见内存泄漏的原因
虽然JavaScript 会自动垃圾收集,但是如果我们的代码写法不当,会让变量一直处于“进入环境”的状态,无法被回收。下面列一下内存泄露常见的几种情况。
全局变量引起的内存泄漏
function foo(arg) {
bar = "this is a hidden global variable";
}
实际上是:
function foo(arg) {
window.bar = "this is an explicit global variable";
}
如果bar是仅在foo函数作用域内承载引用,并且你忘记用var来声明的变量,一个意外的全局变量就被创建了。在这个例子中,泄漏一个单一字符串不会有太大害处,但这的确是不好的。
另一种意外全局变量被创建的方式是通过this
function foo() {
this.variable = "potential accidental global";
}
foo();
为了阻止这种错误发生,在你的Javascript文件最前面添加'use strict;'。这开启了解析JavaScript的阻止意外全局的更严格的模式
全局变量注意事项
尽管我们讨论了一些意外的全局变量,但是仍有一些明确的全局变量产生的垃圾。它们被定义为不可回收(除非定义为空或重新分配)。尤其当全局变量用于 临时存储和处理大量信息时,需要多加小心。如果必须使用全局变量存储大量数据时,确保用完以后把它设置为 null 或者重新定义。与全局变量相关的增加内存消耗的一个主因是缓存。缓存数据是为了重用,缓存必须有一个大小上限才有用。高内存消耗导致缓存突破上限,因为缓 存内容无法被回收。
闭包引起的内存泄漏
function a(){
var i=0;
function b(){
alert(++i); // 被闭包所引用,不会被回收
}
return b;
}
var c=a();//执行完成以后a函数里面的i变量不能被释放,因为有闭包的维持。当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。
c();
基础的DOM泄漏
当原有的DOM被移除时,子结点引用没有被移除则无法回收。
var select = document.querySelector;
var treeRef = select('#tree');
var leafRef = select('#leaf'); //在COM树中leafRef是treeFre的一个子结点
select('body').removeChild(treeRef);//#tree不能被回收入,因为treeRef还在
解决方法:
treeRef = null;//tree还不能被回收,因为叶子结果leafRef还在
leafRef = null;//现在#tree可以被释放了
dom清空或删除时,事件未清除导致的内存泄漏
<div id="container">
</div>
$('#container').bind('click', function(){
console.log('click');
}).remove();
解决方法:
$('#container').bind('click', function(){
console.log('click');
}).off('click').remove();
//把事件清除了,即可从内存中移除
timer定时器泄漏
var val = 0;
for (var i = 0; i < 90000; i++) {
var buggyObject = {
callAgain: function() {
var ref = this;
val = setTimeout(function() {
ref.callAgain();
}, 90000);
}
}
buggyObject.callAgain();
这个时候你无法回收buggyObject
//虽然你想回收但是timer还在
buggyObject = null;
解决办法,先停止timer然后再回收
//解决方法,先停止定时器
clearTimeout(val);
buggyObject = null;
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。