JS内存泄露
当我们用JS代码创建一个引用类型的时候(以下简称对象),JS引擎会在内存中开辟一块空间来存放数据,并把指针引用交给那个变量。内存是有限的,JS引擎必须保证当开辟的对象没用的时候,把所分配的内存空间释放出来,这个过程叫做垃圾回收,负责回收的叫做垃圾回收器。
内存泄漏是指我们已经无法再通过JS代码来引用到某个对象,但垃圾回收器却认为这个对象还在被引用,因此在回收的时候不会释放它。导致了分配的这块内存永远也无法被释放出来。如果这样的情况越来越多,会导致内存不够用而系统崩溃。
以下几种情况会导致内存泄露
绑定事件没有移除
当页面中元素被移除或替换时,若元素绑定的事件仍没被移除,在IE中不会作出恰当处理,此时要先手工移除事件,不然会存在内存泄露。
下面这种情况,我们移除input
元素之后,但其绑定的事件仍在,垃圾回收器会认为这个对象还是有用的,因此不会回收这个对象,这样就导致当初为这个对象分配的内存无法被释放。
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
document.getElementById("myDiv").innerHTML = "Processing...";
}
</script>
为了避免这种情况的发生,我们可以这样写
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
var btn = document.getElementById("myBtn");
btn.onclick = function(){
// 手动将 btn.onclick 指向 null, 这样在删除 input 对象时,就不会发生内存泄漏
btn.onclick = null;
document.getElementById("myDiv").innerHTML = "Processing...";
}
</script>
innerHTML将对象置为空
用innerHTML将对象置为空时,如果其中的元素被其他引用,也会发生内存泄漏。
尽管我们将div
的innerHTML
赋值为空,但因为引用p
指向div
中的p
元素,这时垃圾回收器会认为p
是有用的,因为被引用着,所以不会回收p
占用的内存,导致内存泄漏。
<div id='myDiv'>
<p id='myP'>innerHTML<p>
</div>
<script type="text/javascript">
var div = document.getElementById("myDiv");
var p = document.getElementById("myP");
div.innerHTML = '';
</script>
闭包
闭包的重要作用之一就是保持状态
正常情况下,一个函数运行结束,其内部的变量就应该被释放。但下面的情况是,函数outer
返回一个匿名函数,这个函数引用变量obj
。这样导致函数outer
运行结束后,它的变量obj
并没有被释放。
function outer(){
var obj = {name:'xiaoxiong'};
return function(){
console.log(obj);
}
}
意外的全局变量
你可以通过加上
'use strict'
启用严格模式来避免这类问题, 严格模式会阻止你创建意外的全局变量
函数运行结束,变量仍然存在,导致泄漏。
function work() {
bar = "this is a hidden global variable";
}
// 上面的函数等价于
function work(arg) {
window.bar = "this is an explicit global variable";
}
现在我们总结一下,导致内存泄漏的原因大致可以分为两种
- 函数运行结束,其内部的变量仍存在
- 我们删除元素,但元素在内存中仍然存在
导致这两种情况的根本原因就是有其他变量引用这些元素。让垃圾回收器认为这个元素还是有用的,因此想避免内存泄漏,我们应该, 要删除一个元素,就要保证在删除这个元素之前,这个元素不被其他其他元素引用(将引用这个元素的指针指向其他元素或置空)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。