文档章节

IE9关联数组导致内存泄漏测试报告

zTree
 zTree
发布于 2012/08/21 17:28
字数 2150
阅读 927
收藏 10

最近为了满足一部分朋友的需求,给 zTree 提供了 destroy 的方法,用于让 zTree 自行清空。为了检查该方法是否有效,做了一个简单的测试——显示5000个节点然后清空,此操作循环100次,结果发现 IE9 下内存严重暴涨,于是进行了反复筛查,最终锁定了嫌疑犯:关联数组(data[key] = value)导致的内存泄漏!

只找到了嫌疑犯不行,定罪要有证据的,设计了一个简单的模型专门进行这个情况的测试,不排除可能由于我的疏忽得到的错误的结论,因此非常欢迎大家踊跃发表自己的看法,随便喷吧。。。。

【测试模型】

不要DOM和闭包、匿名函数干扰,一个全局变量 data 用于保存生成的数据;一个全局变量max用于设置数据最大条数;一个Function用于创建数据;一个Function 用于销毁数据。两个按钮,分别用于触发这两个Function。

补充:为了进行多种情况对比,因此一共制作了8组创建数据、销毁数据的 Function ,详细见后面的说明。

【测试流程】


【测试环境】

Win7 64位操作系统;IE Tester下的 IE6、8、9;FireFox v14.0.1;Chrome v21.0.1180.79;IE6性能太差,因此设置数据条数 max=100000;其他的浏览器都设置 max=1000000;

【开始测试】

1) 第一组测试:

创建对象:关联数组的 key 值无限递增,绝不重复

销毁对象:递归遍历对象内部属性,逐一清空

var data = new Object();
var i=0,j, max=1000000;

function initJson_1(){
	for (j=i+max; i<j; i++) {
		data["_" + i] = {id:i, name:"name" + i};
	}
}

function clearJson_1(){
	clearItem(data);
}

function clearItem(jsonObj) {
	for (var s in jsonObj) {
		var obj = jsonObj[s];
		if (obj instanceof Array) {
			for(var i=obj.length-1; i>=0; i--) {
				clearItem(obj[i]);
				obj.pop();
			}
		}else if (obj instanceof Object){
			clearItem(obj)
		}else{
		}
		jsonObj[s] = null;
		delete jsonObj[s];
	}
	jsonObj = null;
}

测试结果: 

 

测试分析:

这种递归逐一清空对象属性的方法对于 IE6 和 Chrome 有一定效果,FireFox杯具了直接无响应(缩小max值后可以正常);IE8内存暴涨,貌似与这个清空的方法有关,第三次之后再执行方法就无反应了;IE9内存稳步上升,即使最后刷新页面也仍然占有大量内存。

2) 第二组测试:

创建对象:关联数组的 key 值无限递增,绝不重复

销毁对象:直接将 data 设置为 new Object()

var data = new Object();
var i=0, max=1000000;

function initJson_2(){
	for (j=i+max; i<j; i++) {
		data["_" + i] = {id:i, name:"name" + i};
	}
}

function clearJson_2(){
	data = null;
	data = new Object();
}

测试结果:

  

测试分析:

与第一组对比,很明显清空对象直接设置为 new Object 即可,完全没有必要自己递归逐一清空,那样只会起到反作用(明显降低效率)。这次的清空操作并不会立刻让垃圾回收机制工作,但对于非IE9 的浏览器都能在重新创建对象时进行垃圾回收,IE9继续保持内存增长状态。

3) 第三组测试:

创建对象:关联数组的 key 值固定,每次创建都在固定范围内

销毁对象:直接将 data 设置为 new Object()

var data = new Object();
var i=0,j, max=1000000;

function initJson_3(){
	for (i=0; i<max; i++) {	
		data["_" + i] = {id:i, name:"name" + i};
	}
}

function clearJson_3(){
	data = null;
	data = new Object();
}

测试结果:

  

测试分析:

因为key值被固定了范围,反复测试都会生成同样的key,所以IE9的内存在增长两次后就不再上涨了。另外这次测试也可以看出FireFox 和 Chrome的垃圾回收机制会在其认为需要的时候自动执行。

4) 第四组测试:

创建对象:关联数组的 key 值无限递增,绝不重复

销毁对象:直接将 data 设置为 {}

var data = new Object();
var i=0,j, max=1000000;

function initJson_4(){
	for (j=i+max; i<j; i++) {
		data["_" + i] = {id:i, name:"name" + i};
	}
}

function clearJson_4(){
	data = null;
	data = {};
}

测试结果:

测试分析:

本组测试主要是与第二组测试进行对照,表明释放对象将其设置为 {} 或 new Object() 是没有什么区别的。

5) 第五组测试:

创建对象:关联数组的 key 值无限递增,绝不重复,同时利用 eval 实现 data.key = value方式进行赋值

销毁对象:直接将 data 设置为 {}

var data = new Object();
var i=0,j, max=1000000;

function initJson_5(){
	for (j=i+max; i<j; i++) {
		eval('data._'+i+'= {id:i, name:"name" + i};');
	}
}

function clearJson_5(){
	data = null;
	data = {};
}

测试结果:

 

测试分析:

这次改变只能证明eval 能不用的时候千万别用! 居然把IE9 搞死了;IE8内存很高,但因为无内存泄漏的情况所以没有死掉。而且其他的浏览器在测试时速度也都明显下降。

6) 第六组测试:

创建对象:将 data 设置为 Array,关联数组的 key 值无限递增,绝不重复,且 key 仍为 String

销毁对象:直接将 data 设置为 null

var data = new Object();
var i=0,j, max=1000000;

function initJson_6(){
	data = [];
	for (j=i+max; i<j; i++) {
		data["_" + i] = {id:i, name:"name" + i};
	}
}

function clearJson_6(){
	data = null;
}

测试结果:

 

测试分析:

继续与第二组测试进行对比,会发现data 是 Array 还是 Object,如果都用关联数组的方式,仍然用对象的方式使用,测试结果依旧是唯有IE9不断攀升呀。

7) 第七组测试:

创建对象:将 data 设置为 Array,关联数组的 key 值无限递增,绝不重复,且 key 修改为 number,可以直接使用数组模型

销毁对象:直接将 data 设置为 null

var data = new Object();
var i=0,j, max=1000000;

function initJson_7(){
	data = [];
	for (j=i+max; i<j; i++) {
		data[i] = {id:i, name:"name" + i};
	}
}

function clearJson_7(){
	data = null;
}

测试结果:

测试分析:

采用了纯数组的方式保存value,及时index不断上涨,仍然不会造成浏览器的内存无限上涨,IE9也正常了。

8) 第八组测试:

创建对象:将 data 设置为 Array,关联数组的 key 值固定,每次创建都在固定范围内,且 key 修改为 number,可以直接使用数组模型

销毁对象:利用 pop() 方法逐一删除数组元素,最后将 data 设置为 null

var data = new Object();
var i=0,j, max=1000000;

function initJson_8(){
	data = [];
	for (i=0; i<max; i++) {	
		data[i] = {id:i, name:"name" + i};
	}
}

function clearJson_8(){
	while(data.length>0) {
		data.pop();
	}
	data = null;
}

测试结果:

测试分析:

与第一组测试对比会发现IE8对于用js 逐一清空对象的操作貌似依然有一些性能的损失;IE6最悲催,与第一组测试中的FireFox 一样,在逐一清空对象时倒下了(缩小max值后可以正常)。

【测试总结】

  1. 核心问题,关联数组的操作在IE9下会引起严重的内存泄漏。个人猜测——虽然通过清空data对象的key、value对应,但IE9的内存回收机制依然认为该key-value有关联,并且不会释放空间;所以当key值固定范围后会发现内存上升到一定范围后就停止了。
  2. 清空对象时直接设置为 null、{}、new Object() 就可以了,没必要逐一逐层进行清除,那样只会降低效率。
  3. IE8表现平平,没有突出的作为;IE6整体性能太弱,所以只能降低测试标准。但对于这个关联数组的操作方面没有什么问题,一直都比较稳定。
  4. FireFox仍然只有一个进程控制所有的tab包括其内核,导致测试时每次运行后,都要多等一会儿,看稳定了再记录内存值。并且 FireFox 的内存回收机制貌似有点儿过于频繁,导致了看它的测试结果总是飘飘忽忽的。
  5. Chrome依然优秀,不管是内存占有量、垃圾回收速度、代码运行速度都很好。

【解决建议】

  1. 是不是应该告诉微软修改这个严重的Bug 呢?
  2. 如果能使用Array 就别用这种关联数组了;如果必须使用关联数组,那么尽量避免key值无限增长,至少可以缓解内存泄漏的伤害…
  3. 是否可以考虑自己制作js 的HashMap?这个我还没有时间做测试,但相信应该性能方面会比原生的关联数组慢不少,难道因为IE9 的Bug 就让我们改变整个代码的架构吗???

© 著作权归作者所有

共有 人打赏支持
zTree

zTree

粉丝 831
博文 21
码字总数 21754
作品 1
朝阳
技术主管
私信 提问
加载中

评论(5)

逸风如梦
逸风如梦
不错不错学习了
mark35
mark35
这个测试给力。 js中Array本质也是对象,为何与关联数组性能差别明显呢
zTree
zTree

引用来自“j.* 夜不眠”的评论

这个图是用的啥测试工具

这图是 excel 的图表
戈壁胡杨
这个图是用的啥测试工具
zkool
zkool
学习了
JS高程中的垃圾回收机制与常见内存泄露的解决方法

前言 起因是因为想了解闭包的内存泄露机制,然后想起《js高级程序设计》中有关于垃圾回收机制的解析,之前没有很懂,过一年回头再看就懂了,写篇博客与大家分享一下。如果喜欢的话可以点波赞...

OBKoro1
10/29
0
0
JQuery Tree插件——zTree v3.4 正式版发布

这次 v3.4 主要还是修改一些细节 bug,同时新增了 destroy 方法用于一些特殊需求中执行树的销毁操作,并且这次在制作 destroy 方法的时候无意间发现了 IE9 的内存泄漏问题,并且针对这个问题...

zTree
2012/09/03
6.9K
28
Effective Java 第三版——7. 消除过期的对象引用

Tips 《Effective Java, Third Edition》一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将近8年的时间,但随着Java 6,7,8...

M104
2017/12/27
0
0
C/C++内存问题检查利器—Purify

C/C++内存问题检查利器—Purify http://www.uml.org.cn/

江河海流
2014/05/14
0
0
Ext JS 3.1 发布 - 内存优化、TreeGrid等

该版本在性能、灵活性上有很大的改善,同时增加了一些常用的UI组件,例如 TreeGrid ,还包括经过优化的排版管理、重构 EventManager。 单页的,组合的,web应用程序已经越来越较为普遍,在所...

绿悠悠
2009/12/20
4.5K
2

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 自定义你的空间

通过对你的空间进行界面的自定义能够让你的空间更加出类拔萃。 如果你具有空间管理员权限,你可以修改你空间的颜色配色,添加你自己的空间标识,选择是否在你空间中显示边栏。或者你可以进入...

honeymose
30分钟前
1
0
Ubuntu18.04 安装MySQL

1.安装MySQL sudo apt-get install mysql-server 2.配置MySQL sudo mysql_secure_installation 3.设置MySQL非root用户 设置原因:配置过程为系统root权限,在构建MySQL连接时出现错误:ERROR...

AI_SKI
今天
3
0
3.6 rc脚本(start方法) 3.7 rc脚本(stop和status方法) 3.8 rc脚本(以daemon方式启动)

3.6-3.7 rc脚本(start、stop和status方法) #!/usr/bin/env python# -*- coding: utf-8 -*-# [@Version](https://my.oschina.net/u/931210) : python 2.7# [@Time](https://my.oschina.......

隐匿的蚂蚁
今天
3
0
Cnn学习相关博客

CNN卷积神经网络原理讲解+图片识别应用(附源码) 笨方法学习CNN图像识别系列 深度学习图像识别项目(中):Keras和卷积神经网络(CNN) 卷积神经网络模型部署到移动设备 使用CNN神经网络进行...

-九天-
昨天
5
0
flutter 底部输入框 聊天输入框 Flexible

想在页面底部放个输入框,结果键盘一直遮住了,原来是布局问题 Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("评论"), ...

大灰狼wow
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部