本文需要基本的javascript知识,准确的说,应该是JScript。

学习本文之前,请先学习MSDN文章 Understanding and Solving Internet Explorer Leak Patterns ,如果英文不好,请看中文:理解并解决IE内存泄露

经过上述文章的学习,我们应该对JScript引起的内存泄露有所了解,最主要的有以下几种方式:

  • 循环引用(Circular References) — IE浏览器的COM组件产生的对象实例和网页脚本引擎产生的对象实例相互引用,就会造成内存泄漏。这也是Web页面中我们遇到的最常见和主要的泄漏方式;
  •  内部函数引用(Closures) — Closures可以看成是目前引起大量问题的循环应用的一种特殊形式。由于依赖指定的关键字和语法结构,Closures调用是比较容易被我们发现的;
  •  页面交叉泄漏(Cross-Page Leaks) — 页面交叉泄漏其实是一种较小的泄漏,它通常在你浏览过程中,由于内部对象薄计引起。下面我们会讨论DOM插入顺序的问题,在那个示例中你会发现只需要改动少量的代码,我们就可以避免对象薄计对对象构建带来的影响;

看完教程,又到了让大家抓狂不已的实战演习:

康盛公司出品的山寨社会化网络(SNS)软件UCenter Home ,即 UCH ,有大量的弹出小窗口功能,类似lightbox,但又明显不是,这些小窗口中大部分点击都会导致内存泄露。如发表评论,一般情况下用户发表之后uchome都会引导用户跳转一次,这种lightbox+跳转的方式将使得dom强制reload,在浪费用户大量流量的同时,也变相避免了内存泄露。在某些页面,依然很严重,例如回复评论时如果点击添加表情,每点击一次,内存就会增长8M左右,屡试不爽。

uchome-memory-leak

其相关代码如下:

?View Code JAVASCRIPT
 //显示表情菜单
function showFace(showid, target) {
	var div = $('face_bg');
	if(div) {
		div.parentNode.removeChild(div);
	}
	div = document.createElement('div');
	div.id = 'face_bg';
	div.style.position = 'absolute';
	div.style.left = div.style.top = '0px';
	div.style.width = '100%';
	div.style.height = document.body.scrollHeight + 'px';
	div.style.backgroundColor = '#000';
	div.style.zIndex = 10000;
	div.style.display = 'none';
	div.style.filter = 'progid:DXImageTransform.Microsoft.Alpha(opacity=0,finishOpacity=100,style=0)';
	div.style.opacity = 0;
	div.onclick = function() {
		$(showid+'_menu').style.display = 'none';
		$('face_bg').style.display = 'none';
	}
	$('append_parent').appendChild(div);
 
	if($(showid + '_menu') != null) {
		$(showid+'_menu').style.display = '';
	} else {
		var faceDiv = document.createElement("div");
		faceDiv.id = showid+'_menu';
		faceDiv.className = 'facebox';
		faceDiv.style.position = 'absolute';
		var faceul = document.createElement("ul");
		for(i=1; i<31; i++) {
			var faceli = document.createElement("li");
			faceli.innerHTML = '<img style="cursor:pointer; position:relative;" onclick="insertFace(''+showid+'','+i+', ''+ target +'')" src="image/face/'+i+'.gif" alt="" />';
			faceul.appendChild(faceli);
		}
		faceDiv.appendChild(faceul);
		$('append_parent').appendChild(faceDiv)
	}
	//定位菜单
	setMenuPosition(showid, 0);
	div.style.display = '';
}

练习题:

(初级)请分析上述代码存在哪几种内存泄露,并尝试解决。

(高级)模仿uchome的代码,写几段内存泄露的javascript