锁定老帖子 主题:EXT的destroy方法是不是存在漏洞?
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-18
利用 http://fins.iteye.com/blog/172891 提到的工具,在IE下对EXT进行测试 只是一个简单的页面,页面内只是简单的定义一个简单的window ,如下 var win=new Ext.Window({title:"my window", width:400, draggable : false, shadow : false, resizable : false, shim :false, autoDestroy : true, height:300}); 关闭这个window时 产生很多ie无法自动回收的孤立结点 每次创建 关闭 创建 关闭 .... 孤立结点都会越来越多 也许这是IE的错 但是EXT不应该忽视IE的 毕竟IE的占有率在那里放着呢 还请大家帮忙分析分析 我看了一下 window/panel的destroy方法似乎确实存在着一些缺陷啊 我重写了 window的destroy方法,效果提升一些,一些顽固结点可以删除了 但是还剩下一下更加顽固的结点无法删除 Ext.Window.prototype.beforeDestroy = function(){ Ext.Window.superclass.beforeDestroy.call(this); Ext.destroy( this.header, this.tbar, this.bbar, this.footer, this.body, this.bwrap, this.focusEl, this.toolTarget, this.resizer, this.dd, this.proxy, this.mask ); this.header=null; this.tbar=null; this.bbar=null; this.footer=null; this.body=null; this.bwrap=null; this.focusEl=null; this.toolTarget=null; this.resizer=null; this.dd=null; this.proxy=null; this.mask=null; } 这个问题如果不弄明白, 在一个复杂的ext页面内,随着操作的增加 内存消耗也将越来越大. deskto那个例子里的 窗口 大家打开关闭打开关闭 几个来回之后内存占用就会达到6 7十M了. 我怀疑 ext的各个组件的destroy方法内部的实现考虑的不够全面, 销毁内容 和销毁顺序 不当造成部分元素无法销毁. 希望大家能够一起讨论分析一下ext的问题到底处在哪里 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-03-18
jack要让我疯狂了!!!!
为了找出问题所在 我一行行的分析 2.02版本代码的 太辛苦了 看到一个地方彻底崩溃了 Template.js 204行 return returnEl ? Ext.get(newNode, true) : newNode; 注意 Ext.get(newNode, true) 再来看 Ext.get 方法的代码 Element.js 2880行 El.get = function(el){ var ex, elm, id; if(!el){ return null; } if(typeof el == "string"){ // element id if(!(elm = document.getElementById(el))){ return null; } if(ex = El.cache[el]){ ex.dom = elm; }else{ ex = El.cache[el] = new El(elm); } return ex; }else if(el.tagName){ // dom element if(!(id = el.id)){ id = Ext.id(el); } if(ex = El.cache[id]){ ex.dom = el; }else{ ex = El.cache[id] = new El(el); } return ex; }else if(el instanceof El){ if(el != docEl){ el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid, // catch case where it hasn't been appended El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it } return el; }else if(el.isComposite){ return el; }else if(Ext.isArray(el)){ return El.select(el); }else if(el == document){ // create a bogus element object representing the document object if(!docEl){ var f = function(){}; f.prototype = El.prototype; docEl = new f(); docEl.dom = document; } return docEl; } return null; }; // 省去一些..... Ext.get = El.get; 我是绞尽脑汁也没弄明白那个true是做什么的 我怀疑这个地方jack弄错了 他本意可能是要给 get弄一个是否从cache里取对象的参数吧 但是没有写. |
|
返回顶楼 | |
发表时间:2008-03-18
ext1.1 里启用垃圾回收后,等30秒才从Element的cache里清除。
刷新页面后内存还占用? |
|
返回顶楼 | |
发表时间:2008-03-18
问题的根本原因找到了
一会儿单独发帖讨论 |
|
返回顶楼 | |
发表时间:2008-03-18
下面这段代码也有问题
看来 ext的 Ext.destroy 果然不够强大 问题还是出在事件管理方面 疑惑中 <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="../resources/css/ext-all.css" /> <script type="text/javascript" src="../adapter/ext/ext-base.js"></script> <script type="text/javascript" src="../ext-all.js"></script> <script type="text/javascript"> function alertMsg(){ alert('click div c'); } function addEventDiv(){ if (!Ext.get("div1") ){ return; } // 使用下面这种方式注册事件 , 那么ext无法正确的移除 Ext.get("div1").on("click",alertMsg); } Ext.onReady(function(){ Ext.get("btn1").on("click",addEventDiv); Ext.get("btn2").on("click",function(){ Ext.destroy(Ext.get("div1")); }); }); </script> </head> <body > <input id="btn1" type="button" value=" 为 div1 添加事件 " /> <input id="btn2" type="button" value=" 移除 div1 " /> <div id="div1">I'm div 1</div> </body> </html> |
|
返回顶楼 | |
发表时间:2008-03-18
前几天也研究过这里的代码,看不出漏洞在那,lisenter的移除,节点的移除都是正确的。。。
|
|
返回顶楼 | |
发表时间:2008-03-18
en 代码上确实没找到什么问题
但是实际情况就是无法移除 而如果用下面的方法给上面代码中的 div注册事件 那么就可以移除: Ext.get("div1").on("click",function(){ alertMsg() }); |
|
返回顶楼 | |
发表时间:2008-03-18
但其实ext已经用传入的function包装了一个新的function,然后才绑定到节点去。 |
|
返回顶楼 | |
发表时间:2008-03-18
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <link rel="stylesheet" type="text/css" href="/script/yuiExt/resources/css/ext-all.css" /> <script type="text/javascript" src="/script/yuiExt/adapter/ext/ext-base.js"></script> <script type="text/javascript" src="/script/yuiExt/ext-all.js"></script> <script type="text/javascript"> function alertMsg(){ alert('click div c'); } function addEventDiv(){ if (!Ext.get("div1") ){ return; } // 使用下面这种方式注册事件 , 那么ext无法正确的移除 Ext.get("div1").on("click",alertMsg); } Ext.onReady(function(){ Ext.get("btn1").on("click",addEventDiv); Ext.get("btn2").on("click",function(){ Ext.destroy(Ext.get("div1")); alert(alertMsg._handlers.length); alert(alertMsg._handlers[0][0]); alert(alertMsg._handlers[0][1]); alert(alertMsg._handlers[0][2]); }); }); </script> </head> <body > <input id="btn1" type="button" value=" 为 div1 添加事件 " /> <input id="btn2" type="button" value=" 移除 div1 " /> <div id="div1">I'm div 1</div> </body> </html> 发现问题在于ext的 wrap function,就是listener是global的话就会有问题。 见 EventManager.js的140行: fn._handlers = fn._handlers || []; fn._handlers.push([Ext.id(el), ename, h]); 这里给传入的listener加了_handlers属性,stopLisener负责清除,那么就能正确的处理。 但是destroy直接调用了E.purgeElement...,这个方法好像没办法看到原来的listen,所以,没办法正确的清除_handlers,而_handlers引用了element |
|
返回顶楼 | |
发表时间:2008-03-18
nihongye 的分析是正确的。
on的加入是通过EventManager的addListener方法来做的,这里在每个fn上绑定了_handlers,purgeElement的时候通过Ext.lib.Event的removeListener方法, 见300行 delete listeners[index][this.WFN]; delete listeners[index][this.FN]; 但是这里是只是删除了fn,没有清楚掉里面的handlers,而handlers有el的引用,因为没法清楚对象.而这个时候fn也就是alertMsg是在window下的,我测了一下,单纯删除他是没用的,必须wrap一下,所以出现了你说的必须用function(){ alertMsg() } 才正确的情况 |
|
返回顶楼 | |