as学习笔记(二十)--深入谈为什么要removelistener
sshong 发表于2008年7月6日 12:12:00 更新于2008年7月7日 19:52:00
预备:
as3中的资源管理与GC
as3中的Class对象和Function对象

很多as3开发人员在博客中都有相关gc以及资源管理的文章,不管作者又没有深入的去研究或者仔细的考虑抑或是直接从别人处摘抄,我想有些问题还是要澄清的透彻好!

注:本文通篇以
objA.addEventListener(objB.func)
为研讨对象

问题一、为什么要removelistener
很多人都知道在addlistener之后,最好手工removelistener一下,否则会产生内存问题!它的英文原文是来自as3语言与组件参考,EventDispatcher类的addEventListener方法的一段解释中:

If you no longer need an event listener, remove it by calling removeEventListener(), or memory problems could result. Objects with registered event listeners are not automatically removed from memory because the garbage collector does not remove objects that still have references.

那么这就存在不同关于Objects with registered event listeners的理解

对于
objA.addEventListener(objB.func);
是指objA还是objB?

如果是objB,则该段话可以翻译为
objB=null;
//理解为objB不会被gc清理,因为objB的func是objA的注册侦听

如果是objA,则该段话可以翻译为
objA=null;
//理解为objA不会被gc清理,因为objA注册了侦听器

我在蓝色上开帖,无人问津

自己再仔细察看了gskiner的文章,写得也是有些含糊,黑羽师兄的殿堂之路上在讲弱引用时有些阐述,却也不是那么明确!

我直觉的理解是:objA.addEventListener(objB.func)则objA中有objB的func这个Function对象的引用,进而也就相当于有了对objB这个对象的引用。

终于,在essential as3中的Event Listeners and Memory Management一节,作者有类似的话:
ActionScript’s event architecture is based on two key participants: the listener (either a function or a method) and the object with which that listener registers.Each object that registers a listener for a given event keeps track of that listener by assigning a reference to it in an internal array known as a listener list.
By default, any object that has a reference to a listener maintains that reference until the listener is explicitly unregistered ia the removeEventListener() method. Further-more, the object maintains its reference to the listener even when no other references to the listener remain in the program.

也就是说因为我们在addlistener时将一个函数对象作为一个参数传递给了eventdispather,在eventdispather中就保留了对这个函数对象的引用并存放在一个叫listener的内部数组中,进而也就保留了对函数对象所在的实例的引用。

所以objA.addEventListener(objB.func)时,objA保留了对objB的强引用,如果在objA没被gc清理前,objB将永远不会被清理!这也是为什么将listener设置为弱引用或者手工removelistener的原因!

问题二、既然removelistener不是因为objA被listener引用而无法被gc清理,那么为什么将objA设置为null后,objA的listener还在那里执行?

这也是我一直在思考的问题
譬如
loader.addEventListener(ProgressEvent.PROGRESS, onprogress);
loader = null;
function onprogress(evt:ProgressEvent):void
{
    trace(evt.target);
    trace("loading");
}
为什么loader的progress事件还在那里一直执行???

这是我总结的原因,不对之处,大家多多指教
唯一可能的原因就是gc在还没有调用前,已经产生了一个PROGRESS事件,而这个事件有一个target属性就是指向loader!loader有引用计数,即使下一个gc到来,loader不会被清除,如此继续。

综合上述两个问题,可以得出为什么一定要手工removelistern的原因
1、对objB,因为objA中有了对其某Function对象的引用,进而拥有了对其的引用nog,因此如果不remove,objB在objA没被清理之前永远得不到清理。这也正是最好把listener设置为弱引用的原因!

2、对objA,因为有些事件在gc到来前已经触发,而这个事件中拥有了对objA的引用,因此gc也无法对objA进行清除,因此objA的listener仍然在那里被触发!而即便是把objB设为null也无用,因为1的原因,objB无法被清理

因此,于objA、objB,如果想顺利的被gc清理,都需要手工的removelistener!

终极结论:as3所谓的资源管理一切都是为了减少引用次数,一切都是为了gc兄能够运作正常!

ps:说真的,我对二的原因还是一头浑水,可以参考文章as3的变量作用域与生命周期中的例子,奇怪,真的奇怪阿!
标签:asremovelistener原因分类:As3&Flex阅读:4505
评论
sshong2013年2月19日 23:41
整理博客,现在回答下2这个问题:
因为flash加载是异步的,新开了一个线程去取数据,只不过这个线程对你来说不可见,会一直分发progress事件到具体的某帧上,除非主动unload。
添加评论
您的大名,限长10汉字,20英文(*)
电子信箱(*)
您的网站
正文,限长500汉字,1000英文(*)
验证码(*) 单击刷新验证码
联系我
博客订阅