内存泄漏常见的原因有三种:
1. 闭包
2. 未解除事件绑定
3. 循环引用DOM元素
除此之外,还有一种泄漏原因少有人知,它和innerHTML有关,不过很容易解决。 出现这种内存泄漏需要有三个条件:1. 内存中存在一个未加入DOM树的元素
2. 给这个元素设置innerHTML,注意,必须是能创建元素并且绑定了DOM 0级事件
3. 必须在这个元素加入DOM树前设置它的innerHTML
举个例子:
// 创建一个仅存在于内存中的元素 var el = document.createElement( 'div' ); // 设置innerHTML el.innerHTML = '<a onclick = "testFn()">Test Link</a>' ; // 加入DOM树 document.body.appendChild(el) |
这种写法很常见对吧,但你根本察觉不到有内存泄漏。唯一的隐患在于,当你在一个相同的页面上频繁地用这种方式设置innerHTML,一次又一次,反反复复,没完没了,好吧,其实也没那么多次,总之是很多次之后,就会出现问题了。
肯定有人会说,谁那么蛋疼地总折腾一个元素,其实在ajax泛滥的时代,经常需要动态更新页面,所以这种情况也并非罕见。如果实在不信,这里有两个DEMO页面:
IE innerHTML Memory Leak Demo IE innerHTML Memory Leak Demo
Upon clicking the "Start Leak" button, a script will execute repeatedly which creates a new
element in memory, sets its innerHTML to a string of 2000 tags with onclick events wired up (' Test Link'), and then adds thatto the page.Letting this script run for about 60 seconds, and using Perfmon to monitor memory consumption, you should notice a significant increase in the amount of memory consumed. To see the same script logic that doesn't leak memory, view the No Leak Page.
IE innerHTML Memory Leak Demo (the fix) IE innerHTML Memory Leak Demo (the fix)
Upon clicking the "Start Leak" button, a script will execute repeatedly which creates a new
element in memory and then adds that element to the page. Only after the element has been added to the page, do we set its .innerHTML to a string to 2000 tags with onclick events wired up (' Test Link').Letting this script run for about 60 seconds, and using Perfmon to monitor memory consumption, you should notice that, unlike the Leak Page, memory consumption remains relatively constant.
接着来看怎么解决它:
其实很简单,换个顺序,先把元素加入DOM树,再设置innerHTML。
当然你也可以完全放弃使用innerHTML,这样做好处多多,比如不会存在未解除事件绑定的情况,但貌似完全放弃innerHTML也不现实。。。