标记-清除算法
- 由垃圾回收器维护一系列根节点(代码中被引用的全局变量)列表,在 JS 中,window 或 global 对象就可以看作是一个根结点。由于 window 对象是一直会存在的,所以它和其子对象都会被看作是一直可被追踪的,即这些对象对应的内存块不会被回收。
- 所有的根都会被检查并标记为引用状态,从根出发,递归地检查子结点。所有可被检查到的都视为非垃圾。
- 所有未被标记的内存块都被认为是垃圾内存,即回收器将回收这一块内存并返还给 OS 重新分配。
常见的内存泄漏的原因
虽然JavaScript会自动垃圾收集,但是如果我们的代码没有及时清空一些被调用的东西,就会让变量一直处于无法回收状态。下面列出基本的几种情况。
全局变量引起
function leaks(){
leak = 'xxxxxx';//leak 成为一个全局变量,不会被回收
}
闭包
var leaks = (function(){
var leak = 'xxxxxx';// 被闭包所引用,不会被回收
return function(){
console.log(leak);
}
})()
dom清空,事件没有清除
过去,在某些浏览器(IE6)中,环型的引用无法导致内存的回收,从而可能引起内存的泄漏。因此对于涉及到订阅机制的代码,一旦我们需要删除订阅体,我们就需要显式地将订阅的内容解除引用。虽然现在的主流浏览器都能正确地处理订阅机制引发的这一类的问题,从代码实践上,如果不再需要订阅,我们最好还是显式地取消掉。
var element = document.getElementById('button');
function onClick(event) {
element.innerHtml = 'text';
}
element.addEventListener('click', onClick);
// Do stuff
element.removeEventListener('click', onClick);
element.parentNode.removeChild(element);
// Now when element goes out of scope,
// both element and onClick will be collected even in old browsers that don't
// handle cycles well.
子元素存在引用
子元素还存在引用时,先把子元素释放再释放父元素,否则父元素无法释放。
例子
被遗忘的计时器
var someResource = getData();
setInterval(function() {
var node = document.getElementById('Node');
if(node) {
// Do stuff with node and someResource.
node.innerHTML = JSON.stringify(someResource));
}
}, 1000);
网友评论