垃圾收集
Javascript具有自动垃圾收集机制。
原理是:找到那些不在继续使用的变量,然后释放其占用的内存。为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性执行这一操作。
垃圾收集策略有两种:
1.标记清除(make-and-sweep)
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。
在此之后再被加上标记的变量将被视为准备删除的变量。
- 销毁带标记的值并回收它们所占用的内存空间。
现代浏览器都用这种垃圾回收策略。
2.引用计数
跟踪记录每个值被引用的次数。
- 当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数为1。
- 如果同一个值又被赋给另一个变量,则该值的引用次数再加1。
- 如果包含对这个值的引用变量取得了另外一个值,则这个值得引用次数减1。
- 当这个值得引用次数为0时,就可将其占用的内存空间回收。这样,当垃圾收集器下次再运行时,它会释放那些引用次数为0所占用的内存。
问题:如果循环引用,该对象无法被释放。
老的IE会用这个策略。
减少JavaScript中的垃圾回收
首先,最明显的,new关键字就意味着一次内存分配,例如 new Foo()。最好的处理方法是:在初始化的时候新建对象,然后在后续过程中尽量多的重用这些创建好的对象。
另外还有以下三种内存分配表达式(可能不像new关键字那么明显了):
- {} (创建一个新对象)
- [] (创建一个新数组)
- function() {…} (创建一个新的方法,注意:新建方法也会导致垃圾收集!!)
1.对象object优化
为了最大限度的实现对象的重用,应该像避使用new语句一样避免使用{}来新建对象。
2.数组array优化
将[]赋值给一个数组对象,是清空数组的捷径(例如: arr = [];),但是这种方式又创建了一个新的空对象,并且将原来的数组对象变成了一小片内存垃圾!
建议:将数组长度赋值为0(arr.length = 0)不仅能达到清空数组的目的,并且同时能实现数组重用,减少内存垃圾的产生
3.方法function优化
只要是动态创建方法的地方,就有可能产生内存垃圾。尽量只创建一个函数对象,多次使用。
4. 删除带有事件处理的元素
从文档中删除带有事件处理程序的元素,如果没有手动删除该元素上的事件(addEventListener
或者removeEventListener
),那么原来添加到元素中的事件处理程序极有可能被当作垃圾回收(只是有可能)。参考如下例子:
<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>
当按钮被从页面中移除时,它还带着一个事件处理程序,在
元素中设置innerHTML可以把按钮移走,但事件处理各种仍然与按钮保持着引用联系。
有的浏览器(尤其是IE)在这种情况下不会作出恰当的处理,它们很有可能会将对元素和事件处理程序的引用都保存在内存中。
如果你想知道某个元即将被移除,那么最好手工移除事件处理程序。
<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;
document.getElementById("myDiv").innerHTML="Processing…";
}
</script>