一、全局变量引起的内存泄漏
function func(){ lmw = 123456 //lmw是全局变量,不会被释放 }
二、闭包引起的内存泄漏
function func(){ var lmw = 123456;//闭包环境,不会被释放 function lmw2(){ //就算是一个空函数,也不会释放 } return lmw2 //被暴露在外界,随时可能被引用 }
三、子元素存在引用引起的内存泄漏
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可以被释放了
四、定时器泄露
var timer=null for(var i=0;i<5;i++){ var funcObj = { "handle":function(){ var _this = this; timer = setTimeout(function(){ console.log(_this) _this.handle() },9000) } } } funcObj.handle()
funcObj = null //只是改变funcObj存储在栈里的引用地址,堆里保存的真实对象不会被释放,定时器还在引用 console.log(funcObj)
真正的释放还要清除定时器,再把funcObj = null
clearTimeout(timer) funcObj = null console.log(funcObj)
五、循环引用
function fn() { var a = {}; var b = {}; a.pro = b; b.pro = a; } fn();
以上代码a和b的引用次数都是2,fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,但是在引用计数策略下,因为a和b的引用次数不为0,所以不会被垃圾回收器回收内存,如果fn函数被大量调用,就会造成内存泄露。在IE7与IE8上,内存直线上升。
IE中有一部分对象并不是原生js对象。比如,DOM和BOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略。因此,即使IE的js引擎采用标记清除策略来实现,但js访问的COM对象依然是基于引用计数策略的。
换句话说,只要在老IE中涉及COM对象,就会存在循环引用的问题
var element = document.getElementById("some_element"); var myObject = new Object(); myObject.e = element; element.o = myObject;
这个例子在一个DOM元素(element)与一个原生js对象(myObject)之间创建了循环引用。其中,变量myObject有一个名为e的属性指向element对象;而变量element也有一个属性名为o回指myObject。由于存在这个循环引用,即使例子中的DOM从页面中移除,它也永远不会被回收。
解决方法:
myObject.e= null; element.o = null;
再来看一个在日常开发中容易犯错的例子:
window.onload=function outerFunction(){ var obj = document.getElementById("element"); obj.onclick=function innerFunction(){}; };
这段代码看起来没什么问题,但是obj引用了document.getElementById(“element”),而document.getElementById(“element”)的onclick方法会引用外部环境中的变量,自然也包括obj。
解决方法:
window.onload=function outerFunction(){ var obj = document.getElementById("element"); obj.onclick=function innerFunction(){}; obj=null; };
将变量设置为null意味着切断变量与它此前引用的值之间的连接。当垃圾回收器下次运行时,就会删除这些值并回收它们占用的内存。
在上面描述的循环引用例子,还可以理解成闭包循环引用导致的内存泄漏
当对DOM元素进行其他操作时,仍然要处处留心。只要是将JavaScript对象指定给DOM元素,就可能在旧版本IE中导致内存泄漏。jQuery只是有助于减少发生这种情况的可能性
注意:IE9+并不存在循环引用导致Dom内存泄露问题