鸟食轩
Microsoft .NET[C#] MVP 2003
随笔 - 332, 文章 - 870, 评论 - 5722, 引用 - 356
IE的JScript解析器可能有Memory Leak
在家过完了年,感觉精神很爽。明天大家可能都就上班了,新的一年开始了,希望大家新年新气象
。而其我已经发现一点点新年的灵感了哦~,我原来发现IE中的JScript解释器可能有的Memory Leak的问题,可老是早不到出问题的代码,今天一下就逮到了一个可以复现的case~~
想当初我做那个无刷新的JScript TreeView控件时,硬是被折磨坏了
。IE进程IEXPLORE.EXE的内存使用量常常串到200M左右,搞得我的JScript代码运行狂慢,有的时候展开一个Node需要好几秒钟@_@。
复现这个Bug的代码如下:
<
html
>
<
head
>
<
title
>
IE Memory Leak Bug
</
title
>
</
head
>
<
body
>
<
button
onclick
="GenerateObjects(this)"
>
Append Elements
</
button
>
<
div
id
="container"
></
div
>
<
script
language
="Javascript"
>
function
GenerateObjects(elmt)
{
var
room
=
document.getElementById('container');
for
(
var
i
=
0
; i
<
1000
;
++
i )
{
var
obj
=
new
TestObject('__Object__'
+
i);
room.appendChild(obj.Render(document));
}
}
function
TestObject(name)
{
this
.m_Name
=
name;
this
.m_Description
=
'';
this
.m_Element
=
null
;
this
.toString
=
function
()
{
return
'[class TestObject]';
}
}
function
TestObject.prototype.Render(doc)
{
var
span
=
doc.createElement('SPAN');
*
span.Object
=
this
;
*
this.m_Element = span;
span.Name
=
this
.m_Description;
span.innerText
=
this
.m_Name;
span.style.display
=
'block';
return
span;
}
</
script
>
</
body
>
</
html
>
运行上面的代码,不断的点击"Generate Elements"按钮,IEXPORE.EXE的内存使用量(PM+VM)持续的上涨。这时不管你点"Refresh"还点"Go"按钮,IE的内存使用量始终不会减少
。除非关掉IE在重新打开,内存才能被释放。
问题出在上面示例代码中打"
*
"的那两句话上,只要注释掉任意一句,Refresh页面后,IEXPORE.EXE的内存使用量就会降到刚打开IE是那个水平上。
有兴趣欢迎您测试一下这个例子,看看是不是会Memory Leak?
相关文章:
·
继续来研究JScript解析引擎的GC问题
绿色通道:
好文要顶
关注我
收藏该文
与我联系
posted on 2005-02-15 23:49
birdshome
阅读(5203)
评论(13)
编辑
收藏
评论
292521
#1楼
回复
引用
估计由于互相引用导致引用链有环,解释器无法判断是否为无用对象所至,应该算是ml bug,这种情况是可以感知的
2005-02-16 01:43
|
问题男
#2楼
回复
引用
查看
这个和变成语言采用的垃圾回收算法/机制有关的,JScript采用的还是那个引用计数的算法,这个算法就是有这个天生的缺陷。现在比较成熟的变成语言一般都是采用无用标记回收算法,java和.net用的都是标记回收算法。
2005-02-16 10:22
|
Laser.NET
#3楼
回复
引用
实际上这个bug可能比想象的还让人郁闷。
关于脚本引擎垃圾回收的问题,还不是我这个示例所关心的,因为对于IE来说,在我Refresh或Go了以后,整个页面的域都变了,而这时居然还不能释放在先前所分配的内存,真是让人抓狂。这个时候browser其实不需要care任何的引用,因为都refresh了,只需要release所有先前分配的内存就行了。
而关于引用链有环和垃圾回收机制,在同一个域中的长时间持续运行中来讨论内存使用量比较有意义。
2005-02-16 10:55
|
birdshome
#4楼
回复
引用
试看下面的例子,则可以理解为何不能一概而论的释放先前的对象了:
======= page1.htm =====================================
<html>
<body>
<button onclick="GenerateObjects(this)">Append Elements</button>
<script language="Javascript">
function GenerateObjects(elmt)
{
var obj = new TestObject('__Object__');
w = window.open("page2.htm");
w.SetObject(obj);
obj.m_Name = "modified";
}
function TestObject(name)
{
this.m_Name = name;
}
</script>
</body>
</html>
======= page1.htm end ==================================
======= page2.htm =====================================
<html>
<body>
<button onclick="Check()">Check Elements</button>
<script language="Javascript">
var obj = null;
function Check()
{
alert(obj.m_Name);
}
function SetObject(o)
{
obj = o;
}
</script>
</body>
</html>
======= page2.htm end ==================================
页面间共享对象是被ie所允许的,为了在关闭page1的情况下page2中依旧能有效的使用共享对象,ie采用了有选择的销毁page1产生的对象的策略是可以被理解的,当然也可以采用统统销毁的策略,不过这么一来有可能引发新的问题
回到实际问题,楼主您所示例子的问题出在脚本引擎应该感知对象持有者形成环、而环上对象都是无用对象的情况,在这种情况下不能正确释放内存明显是垃圾回收算法的一个bug
2005-02-16 15:16
|
问题男
#5楼
回复
引用
查看
瓶颈在于你的For循环,很早以前遇到过你说的问题,办法也很简单,不要用对象创建和AppendChild的方法,而使用拼字符串直接赋值给InnerText 的方法会快很多。
而且你的这个例子在不同配置的机器上可能情况不同,有的配置的机器不会出现这个情况。老外早就讨论过这个问题,其实这和我们之前的讨论面向对象和非面向对象一样。技术的许多东西在于你一线间的把握和感觉,你如果一定要把它说成Bug,那也行,就问题本身而言提这个问题有些耍宝:)
W3C DOM vs. innerHTML
http://www.quirksmode.org/dom/innerhtml.html
innerHTML VS DOM.
http://www.developer-x.com/content/innerhtml/
ccBoy
2005-02-16 15:35
|
ccBoy
#6楼
[
楼主
]
回复
引用
查看
@
问题男
你说的对。而且只要我在页面unload的时候能把那个环状引用链表拆开,Refresh后EXPROE.EXE就能释放内存。
<
body
onunload
="ReleaseElements()"
>
...
<
script
language
="javascript"
>
function
ReleaseElements()
{
var
room
=
document.getElementById('container');
var
spans
=
room.all.tags('SPAN');
for
(
var
i
=
0
; i
<
spans.length ;
++
i )
{
spans[i].Object
=
null
;
}
}
</
script
>
不过这样的效率比较差,特别是生成的Elements较多的时候:(
@ccBoy
非常感谢您提供的资料,可是我的开发框架不太能用得上innerText或innerHTML这种模式。因为对于复杂的JS控件,我希望能把UI Element和Logic Object分开,以便于开发和维护。关于那个for只是为了让内存消耗明显些,之所以写出这个:
span.Object
=
this
;
this
.m_Element
=
span;
这样的环状引用,也就是为了建立它们之间的双向联系而已。
现在我希望能有更好的办法来破除IE对环状引用链不能识别的问题,否则逻辑和UI之间不能双向引用还是比较闹心的。
2005-02-16 16:36
|
birdshome
#7楼
回复
引用
这也是没有办法的,谁让引擎的实现基础是com呢
建议,需要建立双向联系时,m_Element之类的成员不存储对象的引用,而存储对象的name或者id之类的间接标示。这么做会令使用时有一个根据标示查找对象的过程,不过应用场合多半不是计算密集型的吧,相信牺牲的效率也不会有多少
2005-02-16 18:06
|
问题男
#8楼
[
楼主
]
回复
引用
查看
这样就回到我原来介绍的那个
无限级Menu中实现逻辑对象和UI元素间关联
的方法上去了,真是鱼和熊掌不能兼得啊:(
2005-02-16 18:18
|
birdshome
#9楼
回复
引用
微软的解释:
http://www.microsoft.com/china/msdn/library/webservices/WebApp/mac0301WebQA.mspx
------------------------------------------------------------------------
问:我有一些关于 JScript® 中垃圾回收的问题。我认为在 Microsoft® Internet Explorer 6.0 中有内存泄漏,但在另一方面,它可能是循环引用问题。在我的代码中,我假设“new Object()”属于 JScript,而“document.createElement”属于 Internet Explorer DOM,因此 JScript 中的垃圾回收器无法释放 DOM 元素。这正确吗?避免这一问题的最佳方法是什么呢?
当您将代码加载到 Internet Explorer 6.0 中并单击“Refresh”时,您可以在“Task Manager”中观察到内存增加:
<html>
<body>
<script type="text/JScript">
for (i=0; i<1000; i++) { // this loop enforces the effect
var model = new Object();
var element = document.createElement("<br>");
model.myElement = element;
element.myModel = model;
model = null;
element = null;
}
</script>
</body>
</html>
答:这不是内存泄漏。您正在页面上创建新文本一千次!这会使页面变大。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。在这里,您将创建许多元素,Internet Explorer 需要保存它们以正确呈现页面。Internet Explorer 并不知道您以后不会运行操纵您刚刚创建的所有这些对象的脚本。
当页面消失时(当您浏览完,离开浏览器时)会释放内存。它不会泄漏。当销毁页面时,会中断循环引用。
2005-04-24 09:43
|
皮皮猪
#10楼
回复
引用
@皮皮猪
微软的解释简直扯淡,我认为解释的人根本没有执行上面那段示例代码。
"您正在页面上创建新文本一千次!这会使页面变大。如果您创建了许多无法获得也无法释放的对象,那才是内存泄漏。"回答问题的人没有理解反复refresh IE内存消耗只增不减,而且即使导航到了别的domain的页面里面后,内存好事不会释放的,已经达到了:"无法获得也无法释放"的境地了!
"当页面消失时(当您浏览完,离开浏览器时)会释放内存。"如果他只是指的关闭浏览器,按么我真的就无话可说了,否则就是windows的bug了。
现在的问题就是,销毁页面(刷新或挑转,反正就是不关闭浏览器)不能释放内存。而且问题比想象的严重。
2005-04-24 11:45
|
birdshome
#11楼
回复
引用
这种问题,只好问Microsoft,IE不释放内存的问题,可能是缓存,也可能是内存汇漏,真不好说。
2005-09-23 12:20
|
chen[未注册用户]
#12楼
[
楼主
]
回复
引用
查看
@chen
对于页面的缓存,如果缓到domain都变了还在缓,我认为就是bug了。
2005-12-07 14:20
|
birdshome
注册用户登录后才能发表评论,请
登录
或
注册
,
返回博客园首页
。
首页
博问
闪存
新闻
园子
招聘
知识库
最新IT新闻
:
·
苹果被指放任开发者违规上传用户通讯簿
·
动视暴雪去年四季度净利9900万美元
·
传在线支付创业公司Stripe融资1800万美元
·
外星人或与自然融为一体难以发现
·
Google 首位雇员离职
»
更多新闻...
最新知识库文章
:
·
如何学习一门新的编程语言?
·
学习不同编程语言的重要性
·
为什么我喜欢富于表达性的编程语言
·
计算机专业的女生为什么要学编程
·
前端必读:浏览器内部工作原理
»
更多知识库文章...
China-pub 2011秋季教材巡展
China-Pub 计算机绝版图书按需印刷服务
导航
博客园
首页
新随笔
联系
订阅
管理
公告
Invert
原创
技术文章和心得,
转载
必须注明来源
"博客园"
!
贴子以"现状"提供,且没有任何担保,同时也没有授予任何权利。
昵称:
birdshome
园龄:
7年10个月
荣誉:
推荐博客
粉丝:
73
关注:
3
搜索
常用链接
我的随笔
我的评论
我的参与
最新评论
我的标签
我的标签
Nokia 6300
(2)
fan
(1)
qq
(1)
腾讯
(1)
输入法
(1)
隐私
(1)
随笔分类
(337)
.NET的私有工具类(2)
(rss)
.NET技术开发相关(34)
(rss)
Asp.net控件开发(14)
(rss)
Debug中的滑铁卢(9)
(rss)
Enjoy Computer :)(27)
(rss)
Jscript&Dhtml开发(162)
(rss)
技术区里的非技术(49)
(rss)
开发中遇到的虫子(14)
(rss)
其它编程相关内容(16)
(rss)
商务智能(BI)开发(10)
(rss)
文章分类
(147)
北京的幸福生活(29)
(rss)
不得不转载(19)
(rss)
乖乖的文章(6)
(rss)
那时还没有blog(4)
(rss)
那是相当八卦(10)
(rss)
手机短信息(1)
(rss)
我们的文章(40)
(rss)
珍贵照片的背景(4)
(rss)
重庆的幸福生活(34)
(rss)
相册
2005 Kick Off @ 涞滩
2006 Kick Off @ 钓鱼城
2006 Offsite @ 四面山
2006 Wedding @ 昆明
2007 Marriage @ 哈尔滨
2007 Offsite @ Thailand
2007 Offsite @ 海南云天
2007 Training @ Seattle
2007 Travelling @ 云南
2008 Travelling @ 天津
乱七八糟的收集
Ex-Colleagues
Jason Lei's Space
.Net Life
(rss)
Jasper
(rss)
Michelles Space
xingd.net
(rss)
玻璃缸
(rss)
短鲷生活
海阔天空
录一室
(rss)
完美的泡菜
(rss)
怡红公子
(rss)
竹叶尖的BLOG
常用链接
Engadget 中文版
PDFCHM eBooks
SitePoint Forums
The Code Project
安利上海直销店
哈尔滨工业大学
哈工大紫丁香
海归论坛
(rss)
沙坪坝区中医院
兄弟情深
没有可乐的日子
葡萄树下不乘凉
(rss)
斯普特尼克
猪头小队长
(rss)
积分与排名
积分 - 3145044
排名 - 6
最新评论
阅读排行榜
推荐排行榜