IE8 Img标签内存泄漏的一种替代方案

        众所周知,Internet Explorer 8 及其以下的版本存在各式各样的问题,是所有web开发人员的恶梦。虽然IE新的版本已经越来越往标准走齐了,普通用户也基本不会再使用低版本的IE浏览器,甚至已经很少使用IE浏览器(大爱FF大笑)。但是国内的某些机构还是会“冥顽不灵”地使用着过时的产品。好吧,客户需求为上,咱们也只能继续地在坑爹的浏览器上调试功能、修改bug。

        最近,经理关注到旧的工程老是占用着大量的内存,并且随着页面切换不断增大,如果不全部关掉IE,永远不会降下来。这不是内存泄漏么,于是乎我上网搜了一堆资料,原来这是IE8的一个大BUG。

        资料显示,IE8中内存泄露的节点类型包括:form、button、input、select、textarea、a、img和object,类型之多让人惊叹。我也没有去逐一验证,只对内存泄漏大户——img标签做了些实验。

        系统环境: Windows 7 64位。   浏览器:Internet Explorer 8。

        我先是随便找了7张大图片,主要找大尺寸的图片。因为工程里要用的都是摄像头拍出来的原图,原始分辨率一般都比较大,图片信息如下:


        然后写了个测试页面,页面显示一个img标签(不改变原图大小),然后启用一个定时器2秒循环换图片:

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

		<title>IMG元素内存泄露测试</title>
		<script type="text/javascript">
			var i = 0;

			// img标签方式
			function changeImage(){
				i++;
				var picIndex = i%7;
				document.getElementById("image").src = "images/"+picIndex+".jpg";
				document.getElementById("imagePath").innerHTML = "images/"+picIndex+".jpg";
			};

			function init(){
				var interval = window.setInterval(changeImage, 2000);
			};
		</script>
	</head>

	<body onload="init();">
		<label id="imagePath"></label>

		<!-- 使用img标签,不改变图片大小,不会发生内存泄漏。 by ljskr -->
		<div><img id="image" /></div>
	</body>

</html> 

        打开任务管理器查看IE占用的内存大小,发现是没有内存泄漏情况的,更换图片的过程中,内存会随图片的大小升高和降低。

        修改一下代码,img标签进行图片缩放或指定大小:

<body onload="init();">
		<label id="imagePath"></label>

		<!-- 使用img标签,并且使用style更改image大小,会发生内存泄漏。 by ljskr -->
		<div><img id="image" style="width:50%; height: 50%;" /></div>
	</body>

        再次查看IE内存占用情况。 这时就发现每次切换一张新的图片,内存都会显著地增大,而且不会降下来。不过,当这7张图片都加载过一次、没有新的图片加载之后,内存就不再增大,而是一直持续在最高的状态(这里7张图片就让IE占用了110M的内存啦):

        更为恐怖的是,如果不把IE窗口关掉,只是关掉这个测试页面的选项卡,内存同样不会降下来。

        知道原因就好办了。如果是不需要进行图片缩放,那么就不会有问题。

        但是如果我就是需要缩小显示呢? 刚开始时的一个想法就是,把图片当成背景图片去显示可不可以,这样就避免了img标签。遗憾的是,背景图片不支持缩放。新的css3倒是增加了背景图片缩放的属性,不过,支持css3的都已经是现代浏览器,不会发生img内存泄漏了(苦笑)。

        经过苦苦追寻,我突然想到了一种方案。不久前使用canvas画图时,记得上面有个drawImage的方法,而google也搞了一个项目ExplorerCanvas,使IE8支持部分canvas的特性。既然如此,说试就试。还是上面的测试页面,图片改为使用canvas标签显示,而不使用img标签。代码如下:

<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

		<title>IMG元素内存泄露测试</title>
		<!-- 使用IE7兼容模式,解决有时不显示canvas图像的问题。 by ljskr -->
		<meta http-equiv="X-UA-Compatible" content="IE=7" />
		<script type="text/javascript" src="./excanvas.js"></script>
		<script type="text/javascript">
			var i = 0;

			// canvas方式
			function changeImage2(){
				i++;
				var picIndex = i%7;
				document.getElementById("imagePath").innerHTML = "images/"+picIndex+".jpg";

				var img = new Image();
				img.src = "images/"+picIndex+".jpg";
				var ctx = document.getElementById("canvasImage ").getContext("2d");
				ctx.clearRect();
				ctx.drawImage(img, 0, 0, 600, 400);
			};

			function init(){
				var interval = window.setInterval(changeImage2, 2000);
			};
		</script>
	</head>

	<body onload="init();">
		<label id="imagePath"></label>

		<!-- 使用canvas画image,内存会回收。 by ljskr -->
		<div><canvas id="canvasImage" width="600" height="400"></canvas></div>
	</body>

</html> 

        再次查看任务管理器,谢天谢地,这下内存就已经看到有下降的过程了。内存变化过程为:开始在切换图片时,内存不断增长,到最大值后持续一小段时间,然后突然降到最低,再重新增长。

        这个虽然没有img原大小显示时那样正常的内存增长曲线,但是至少还能看到有内存下降,更重要的是,在只关掉测试页面选项卡时,内存可以正常释放。


        这里做个小总结:

        1. 如果图片不需要缩放、原图大小显示,那么,请放心地使用img标签。(这里可以延伸出来一个方案就是把大分辨率图片通过其他途径缩小成需要显示的大小,再进行使用。)

        2. 如果图片需要进行缩放,可以使用canvas的画图,可以算是某种程度上的解决了泄漏问题。


        时间仓促,还没有充分验证其在项目中的实际效果。我这只是做了抛砖引玉,欢迎各位大神补充。


转载请标明出处,谢谢!




猜你喜欢

转载自blog.csdn.net/ljskr/article/details/43835415