Ext.TabPanelItem中使用Iframe引起的内存泄露

选择风险
近期我们在产品前台重构中引入了RIA特性。虽然Ajax比其他RIA技术对于开发人员技术水平的要求较高,开发代价更大,但由于产品特性需要我们仍然采用了Ajax技术,并在众多框架中选择了Prototype(1.5.1)和Ext(1.0.1a)组合。在企业级应用开发中做出这样的抉择是需要承担一定的风险的。

如期而至的问题
不出所料,重构工作开展不过两个星期,客户端浏览器的性能问题便凸现出来,使重构进程陷入僵持状态。暂时撇开客户端代码运行速度不说,IE(6 sp2)和Fx(2.0.0.4)浏览器出现了不同程度的JavaScript内存泄露,使得客户端浏览器在浏览系统页面一段时间后会消耗大量客户端资源以至浏览器的浏览速度低下甚至瘫痪。使框架问题还是我们编写的客户端代码存在问题呢?我们首先带着这个问题展开了一系列的测试。

经过初步观察,在系统主界面中每打开一个包含了Ext.Grid(以下简称grid)控件的Ext.TabPanelItem(以下简称tab),浏览器(IE、Fx)占用的内存资源就会飙升1-4M,且关闭Ext.TabPanelItem后内存并不会被回收。如此,每次开启10个Ext.TabPanleItem再将之关闭,反复数次之后,浏览器所占用的资源已经高达数百兆。浏览器内存占用提高的问题暂不考虑,因为tab中嵌入了iframe(由于系统页面结构的特殊性和接口问题,没有利用ajax请求向tab中装载页面内容),而iframe中的页面加载了Prototype和Ext的js文件(总共大约600K),假设框架加载需要分配1-4M的内存空间也是合理的。但关闭tab后内存不被回收,且开启新tab时浏览器内存占用继续增长,则可以肯定地判断为内存泄露。是何种原因导致了内存泄露呢?

IE/Fx的bug,iframe惹祸
经过进一步的观察,我们发现IE和Fx的内存泄露现象存在着差异,而浏览器瘫痪的时机也有着很大不同。

具体表现如下:

IE:每开启一个tab,IE的内存占用量即提高1-4M。关闭tab,内存占用量不会下降。继续操作,直至浏览器瘫痪,内存占用量仍不下降。

Fx:每开启一个tab,Fx的内存占用量提高1-4M。关闭tab,内存占用量不会下降。但连续关闭几个tab后,浏览器陷入假死状态,cpu占用率达到50%,数秒后恢复正常。tab全部关闭后,继续操作,随着tab的添加Fx的内存占用量又逐渐增加。

解决办法
综上,可以得到这样的结论,IE下确实存在着内存泄露问题,而Fx下并非内存泄露导致浏览器假死。

随后,我在Ext的官方网站论坛上找到了关于iframe与tab混用时会发生Memory leak的帖子。Ext核心开发人员Jack的回答是,TabPanelItem在关闭时并不会对自定义到tab中的元素做特殊处理,这部分工作必须在控件外来完成。另一方面,相关资料称IE在iframe元素的回收方面存在着bug,在通常情况下应该将该元素的src属性值修改为”abort:blank”,并手工将其从DOM树上移除,然后把脚本中引用它的变量置空并调用CollectGarbage()就可以避免iframe不能正常回收所造成的内存泄露。

按照上述方法,在tab的close事件中添加了iframe的销毁代码,IE的内存泄露问题得以解决。

但是,Fx的问题仍然无法得到解决,即关闭tab后CPU占用率激增并持续数秒。无奈之下我测试了Linux下的Firefox以及Windows版本的Firefox 3 alpha,并未出现此问题。初步断定,着个问题应该是Firefox 2.0.0.4在DOM元素回收性能方面的BUG。至于在Fx下关闭tab并不会立即释放内存也得到了官方解释,Fx会缓存一部分页面数据在内存中,以得到较好的性能。

“至尊”级浏览器,Safari
此前我对苹果发布的windows版本Safai3还持有不屑一顾的态度,因为他们的发言人实在太过狂妄的发言,自称Safari是世界上最好的浏览器,未把任何浏览器放在眼里。我一向不喜欢自吹的人,却又对他们发言人的狂言感觉好奇,另一方面希望测试一下产品的跨浏览器能力,便索性下载了Safari 3 for windows。结果令我瞠目结舌,Safari处理JavaScript的速度绝非IE和Fx(包括他们的最新版本IE7和Fx3 alpha)所能及,绝对可以堪称一流的页面渲染能力。为程序员说句心里话,如果所有浏览器的页面渲染速度能达到Safari的水准,我们在AJAX RIA应用构建上将有更大的发挥空间。我着实为Safari带来的RIA极速浏览体验快感兴奋了一把。不夸张地说,Safari至少可以算个浏览器的准至尊吧。

Ext的js包使用注意事项
在通常情况下,使用ext-all.js就可以了,但是当一个页面需要包含多个iframe,且iframe的资源指向需要使用Ext的页面时,被嵌入的页面尽量不要使用Ext-all.js了,而是使用ext-core.js并从Ext的package目录中加载你所需要的js包。除非你确定你的客户使用Safari或者Fx3来浏览,否则性能会大打折扣。

作者:冰咖啡
from:http://icedcoffee.blogbus.com/logs/6489320.html


~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

文章所提到的iframe内存回收的方案下文给出了一个完整参考:

项目中用到一个IFRAME做页面跳转前的处理,运行时发现每次通过IFRAME并关闭页面后,IE的内存会增加3M左右,调查发现是IFRAME没有释放掉,所以对代码做了修改:




作者:gaohades
from:http://www.cnblogs.com/gaohades/archive/2009/07/24/1415811.html

此条目发表在sitebuild分类目录,贴了, , 标签。将固定链接加入收藏夹。

发表评论

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据