浏览器内存泄漏问题的跟踪与解决
在Ajax盛行以前,浏览器内存泄漏不是什么大问题,因为都是通过页面跳转和刷新来进行与服务端的交互,而现在情况不一样了,很多应用广泛应用Ajax和iframe,结果内存泄漏成了很多富客户端应用的隐患。比如我现在参与的项目长期以来一直深受内存泄漏问题的困扰,测试人员常常抱怨,因为他们是使用软件最多的人员,常常几个小时后的点击就让浏览器占用的内存达到几百M,有时甚至到G,但我们开发人员始终没有很好解决这个问题,归结其原因,主要是开发人员没有关注内存泄漏的意识,开发时只管功能实现,不管是否造成了内存泄漏,但问题积攒到一定级别时,解决问题的成本就不小了。同时,检测内存泄漏的工具和手段确实有限,仅有的两个工具(JavaScript Memory Leak Detector和 sIEve )都不太好用,不像Java里面的一些工具能精准定位。另外,项目里大量使用了Ext和Jquery框架,这些框架本身就存在内存泄漏的问题,因此,需要常常深入到这些框架的源码,这自然提高了解决问题的难度。
这块骨头难啃,但必须啃下不可,因为造成的影响实在太恶劣,此项目将为服务与千万级别的客户,如果让这千万级别的客户都去忍受动辄占用几百M的应用,实在说不过去。有关内存泄漏的文章很多,比如《Understanding and Solving Internet Explorer Leak Patterns》是最权威一篇,里面提到了几个造成内存泄漏的模式,摘抄如下:
但如果通过这么几个模式去check项目里的代码简直如大海捞针,我只有凭经验预测最有可能泄漏的几个点,再通过排除法,去掉先相关代码,再看内存是否泄漏。我预计会有以下几种情况造成泄漏:
??????? 频繁操作iframe?
??????? 动态创建DOM?
??????? 事件绑定?
??????? Ext框架本身
经过排查发现项目这么几个点内存泄漏较为严重:
??????? 对iframe里面的页面大量绑定键盘事件?
??????? 在iframe里面的页面动态创建DOM?
??????? iframe的刷新?
??????? Ext本身
对于这些问题我的解决方案如下:
1. 离开iframe里的页面之前删除所有的事件绑定,删除所有动态创建的DOM
2. 刷新iframe内容之前调用
Ext.getDOC() getDoc : function(){ //原实现 //return Ext.get(document); //修改后 var f = function() { }; f.prototype = Ext.Element.prototype; var docEl = new f(); docEl.dom = document; return docEl; }?
??? 具体是什么原因还没查清,不过修改后确实内存释放了不少。
4. 修改Ext垃圾回收相关代码。及时删除垃圾回收的轮询。
?
修改以上点后,内存基本保持在100多M,相比以前改进了不少,但并没完全消除内存泄漏,因此此问题的跟踪还得继续,力争将内存泄漏减为0