内存泄漏是一个常见的性能问题,常常会导致程序的崩溃,运行缓慢,高延迟或者其他的一下问题;
内存泄漏:
内存泄漏是指分配给应用的内存不能被重新分配,即使在内存已经不被使用的时候。正常情况下,垃圾回收器在DOM元素和event处理器不被引用或访问的时候回收它们。但是,IE的早些版本(IE7和之前)中内存泄漏是很容易出现的,因为内存管理器不能正确理解Javascript生命周期而且在周期被打破(可以通过赋值为null实现)前不会回收内存。
Javascript 中的垃圾收集机制:
javascript具有自动垃圾收集机制,也就是说,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理;垃圾收集器会按照固定的时间间隔,周期性的执行这一操作;
javascript中有两种垃圾回收方法:标记清除,引用计数;
javascript中内存泄漏的几种方式
1,意外的全局变量
JavaScript 宽容性的一点表现在它处理未声明变量的方式上:一个未声明变量的引用会在全局对象中创建一个新的变量。在浏览器的环境下,全局对象就是 window
function leaks(){
leak = 'xxxxxx';//leak 成为一个全局变量,不会被回收
}
另一种意外全局变量被创建的方式是通过this:
function foo() {
this.str= "this is a global";
}
//在这里str也是一个全局变量,只不过比较隐晦罢了
foo();
为了阻止这种错误发生,在你的Javascript文件最前面添加’use strict;’。这开启了解析JavaScript的阻止意外全局的更严格的模式。
2,闭包引起的内存泄漏
闭包可以导致内存泄漏是因为内部方法保持一个对外部方法变量的引用,所以尽管方法返回了内部方法还可以继续访问在外部方法中定义的私有变量。对Javascript程序员来说最好的做法是在页面重载前断开所有的事件处理器。
var getBIBAO= (function(){
var leak = ‘1234567’;// 被闭包所引用,不会被回收
return function(){
console.log(leak);
}
})()
1234567
3,循环引用
简单来说假如a引用了b,b又引用了a,a和b就构成了循环a和b循环引用:
var a=new Object;
var b=new Object;
a.r=b;
b.r=a;
a循环引用自己:
var a=new Object;
a.r=a;
用很常见且大部分情况下是无害的,但当参与循环引用的对象中有DOM对象或者ActiveX对象时,循环引用将导致内存泄露。我们把例子中的任何一个new Object替换成document.getElementById或者document.createElement就会发生内存泄露了。
4,dom清空或删除时,事件未清除导致的内存泄漏
<div id="container">
</div>
$('#container').bind('click', function(){
console.log('click');
}).remove();
// zepto 和原生 js下,#container dom 元素,还在内存里jquery 的 empty和 remove会帮助开发者避免这个问题
12345678
<div id="container">
</div>
$('#container').bind('click', function(){
console.log('click');
}).off('click').remove();
//把事件清除了,即可从内存中移除
1234567
5,被遗忘的定时器或者回掉
在javascript中,使用set Interval之后,不把这个清除掉容易产生内存泄漏的问题;
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
// Do stuff with node and someResource.
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
这个例子表明了跳动的计时器可能发生什么:计时器使得节点或数据的引用不再被需要了。代表node的对象将来可能被移除,使得整个块在间隔中的处理不必要。然而,处理函数,由于间隔仍然是活跃的,不能被回收(间隔需要被停掉才能回收)。如果间隔处理不能被回收,它的依赖也不能被回收。那意味着可能存储着大量数据的someResource,也不能被回收。
6,由于子元素的存在引起的内存泄漏问题
- 黄色是指直接被 js变量所引用,在内存里
- 红色是指间接被 js变量所引用,如上图,refB 被 refA 间接引用,导致即使 refB 变量被清空,也是不会被回收的
- 子元素 refB 由于 parentNode 的间接引用,只要它不被删除,它所有的父元素(图中红色部分)都不会被删除