2008-03-18
EXT的destroy方法是不是存在漏洞?
EXT的destroy方法是不是存在漏洞?销毁的不彻底?
利用
http://fins.javaeye.com/blog/172891
提到的工具,在IE下对EXT进行测试
只是一个简单的页面,页面内只是简单的定义一个简单的window ,如下
关闭这个window时 产生很多ie无法自动回收的孤立结点
每次创建 关闭 创建 关闭 ....
孤立结点都会越来越多
也许这是IE的错 但是EXT不应该忽视IE的 毕竟IE的占有率在那里放着呢
还请大家帮忙分析分析
我看了一下 window/panel的destroy方法似乎确实存在着一些缺陷啊
我重写了 window的destroy方法,效果提升一些,一些顽固结点可以删除了
但是还剩下一下更加顽固的结点无法删除
这个问题如果不弄明白, 在一个复杂的ext页面内,随着操作的增加 内存消耗也将越来越大.
deskto那个例子里的 窗口 大家打开关闭打开关闭 几个来回之后内存占用就会达到6 7十M了.
我怀疑 ext的各个组件的destroy方法内部的实现考虑的不够全面, 销毁内容 和销毁顺序 不当造成部分元素无法销毁.
希望大家能够一起讨论分析一下ext的问题到底处在哪里
利用
http://fins.javaeye.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的问题到底处在哪里
评论
gdipkf1986
2008-03-19
呵呵,等着楼主的解决方法.自己目前还没有这个能力去做这个事情.
fins
2008-03-19
找到解决办法了 一会发新帖
=======================
收回上面的话 虽然可以解决 但是会打乱ext的依赖 再想想先
=======================
收回上面的话 虽然可以解决 但是会打乱ext的依赖 再想想先
znjq
2008-03-19
我的意思是为了证明问题原因注释掉测试一下。
还是等ext自己去解决,或者自己小心使用了。呵呵
还是等ext自己去解决,或者自己小心使用了。呵呵
nihongye
2008-03-18
引用
觉的还是这2行的问题
Java代码 复制代码
1. fn._handlers = fn._handlers || [];
2. fn._handlers.push([Ext.id(el), ename, h]);
fn._handlers = fn._handlers || [];
fn._handlers.push([Ext.id(el), ename, h]);
这里的_handlers只在Eventmanager里面stopListening的时候做判断才用到,别的地方没看到过。感觉这里设计的有点多余,别的地方removeListener的时候又没有处理这块. 可能eventmanager和ext-base是不同人写的,呵呵。
你把这2行注释掉,就不会出现上面的内存问题了
Java代码 复制代码
1. fn._handlers = fn._handlers || [];
2. fn._handlers.push([Ext.id(el), ename, h]);
fn._handlers = fn._handlers || [];
fn._handlers.push([Ext.id(el), ename, h]);
这里的_handlers只在Eventmanager里面stopListening的时候做判断才用到,别的地方没看到过。感觉这里设计的有点多余,别的地方removeListener的时候又没有处理这块. 可能eventmanager和ext-base是不同人写的,呵呵。
你把这2行注释掉,就不会出现上面的内存问题了
注释掉恐怕不行,因为实际有些地方使用了el.un(...,fn)的方式停止监听,在ext的论坛上搜索_handlers destory,可以找到一篇11份的帖子提到这个问题,ext的开发人员在一些相关的回答中隐约说了要解决这个问题。假如ext本身保证了以非global function作为监听器,或者我们小心点去避免这个问题,呵呵。
znjq
2008-03-18
觉的还是这2行的问题
这里的_handlers只在Eventmanager里面stopListening的时候做判断才用到,别的地方没看到过。感觉这里设计的有点多余,别的地方removeListener的时候又没有处理这块. 可能eventmanager和ext-base是不同人写的,呵呵。
你把这2行注释掉,就不会出现上面的内存问题了
fn._handlers = fn._handlers || [];
fn._handlers.push([Ext.id(el), ename, h]);
这里的_handlers只在Eventmanager里面stopListening的时候做判断才用到,别的地方没看到过。感觉这里设计的有点多余,别的地方removeListener的时候又没有处理这块. 可能eventmanager和ext-base是不同人写的,呵呵。
你把这2行注释掉,就不会出现上面的内存问题了
fins
2008-03-18
我刚才看了一下 purgeElement 方法到最后还是调用了 stopLisener吧
=====================
(又仔细看了一下 没掉 呵呵 un方法调用了 但是destroy里的那个 removeAllLisener没有调 呵呵 我看错了
)
我觉得问题的关键是 ext的一个地方设计的有问题
他应该先 wrap 后备份
也就是说 ext-base.js 第240行的
这个操作应该早做 不应该在这一部里做
应该在 eventmanage.js 里的 addListener(205行)里做
先wrap 之后完全操作的是这个wrap之后的function
=====================
(又仔细看了一下 没掉 呵呵 un方法调用了 但是destroy里的那个 removeAllLisener没有调 呵呵 我看错了
我觉得问题的关键是 ext的一个地方设计的有问题
他应该先 wrap 后备份
也就是说 ext-base.js 第240行的
var wrappedFn = function(e) {
return typeof Ext != 'undefined' ? fn(Ext.lib.Event.getEvent(e)) : false;
};
这个操作应该早做 不应该在这一部里做
应该在 eventmanage.js 里的 addListener(205行)里做
先wrap 之后完全操作的是这个wrap之后的function
fins
2008-03-18
谢谢2位 你们提供的线索很重要啊 呵呵
我打算想办法改写一下ext的这个问题
到时候有不明白的还要请教2位 谢谢了先
另外最近我的一个工作就是优化ext (减少EXT对内存和cpu资源的占用)
由于之前并不是很了解ext的架构 所以想听听大家的建议
希望有同好者可以和我一起研究 谢谢了
我打算想办法改写一下ext的这个问题
到时候有不明白的还要请教2位 谢谢了先
另外最近我的一个工作就是优化ext (减少EXT对内存和cpu资源的占用)
由于之前并不是很了解ext的架构 所以想听听大家的建议
希望有同好者可以和我一起研究 谢谢了
znjq
2008-03-18
nihongye 的分析是正确的。
on的加入是通过EventManager的addListener方法来做的,这里在每个fn上绑定了_handlers,purgeElement的时候通过Ext.lib.Event的removeListener方法,
见300行
但是这里是只是删除了fn,没有清楚掉里面的handlers,而handlers有el的引用,因为没法清楚对象.而这个时候fn也就是alertMsg是在window下的,我测了一下,单纯删除他是没用的,必须wrap一下,所以出现了你说的必须用function(){
alertMsg()
}
才正确的情况
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()
}
才正确的情况
nihongye
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
nihongye
2008-03-18
但其实ext已经用传入的function包装了一个新的function,然后才绑定到节点去。
fins
2008-03-18
en 代码上确实没找到什么问题
但是实际情况就是无法移除
而如果用下面的方法给上面代码中的 div注册事件 那么就可以移除:
但是实际情况就是无法移除
而如果用下面的方法给上面代码中的 div注册事件 那么就可以移除:
Ext.get("div1").on("click",function(){ alertMsg() });
nihongye
2008-03-18
前几天也研究过这里的代码,看不出漏洞在那,lisenter的移除,节点的移除都是正确的。。。
fins
2008-03-18
下面这段代码也有问题
看来 ext的 Ext.destroy 果然不够强大
问题还是出在事件管理方面
疑惑中
看来 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>
fins
2008-03-18
问题的根本原因找到了 :)
一会儿单独发帖讨论
一会儿单独发帖讨论
nihongye
2008-03-18
ext1.1 里启用垃圾回收后,等30秒才从Element的cache里清除。
刷新页面后内存还占用?
刷新页面后内存还占用?
fins
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行
我是绞尽脑汁也没弄明白那个true是做什么的
我怀疑这个地方jack弄错了
他本意可能是要给 get弄一个是否从cache里取对象的参数吧
但是没有写.
为了找出问题所在 我一行行的分析 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里取对象的参数吧
但是没有写.
发表评论
提醒: 该博客已发表在公共论坛,博客所有留言会成为论坛回贴,留言请注意遵守论坛发贴规则
- 浏览: 706232 次
- 性别:

- 来自: 小胖儿的大城

- 详细资料
搜索本博客
我的相册
David Recordon
共 63 张
共 63 张
链接
最新评论
-
EXT 2 绚丽表格 背后的 ...
楼上的真是锐道的好员工啊 dorado整体表现确实不错 但是没有哪个单项可以用 ...
-- by fins -
EXT 2 绚丽表格 背后的 ...
http://www.bstek.com/dorado5/performance ...
-- by hotbarsmu -
[GT-Grid]列表组件 GT-Gr ...
如果一切正常 下周应该会出一个前后台结合的例子 例子已经在编写中了 不过为了 ...
-- by fins -
[GT-Grid]列表组件 GT-Gr ...
fins什么时候会有和服务端结合的版本呢?您可以给个简单的案例吗?谢谢
-- by hgq0011 -
[GT-Grid]列表组件 GT-Gr ...
这个是和ecside完全不同的产品 自然看起来也会面目全非了 呵呵
-- by fins






评论排行榜