在过去一个月左右的时间里,我一直在教自己动作脚本3,最近遇到了一个问题,一个物体在我认为被删除之后仍在继续做事。我发现问题是由使用默认值useWeakReference = false的事件监听器引起的,我想知道为什么这是默认值。 不使用弱引用有什么好处?为什么这是默认的? 在我看来,一般来说你想要使用弱引用,所以我必须遗漏一些东西。
谢谢, -Ted
答案 0 :(得分:6)
重点是,弱引用很昂贵......它们都比较慢并占用更多空间......这里有一些基准代码:
package {
//{ region imports
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.system.System;
import flash.utils.*;
//} endregion
public class Main extends Sprite {
public function Main():void {
switch (0) {
case 0: this.benchmarkDispatchers(false); break;
case 1: this.benchmarkDispatchers(true); break;
case 2: this.benchmarkDictionaries(false); break;
case 3: this.benchmarkDictionaries(true); break;
}
}
private function benchmarkDictionaries(weakKeys:Boolean, size:uint = 1000000):void {
var a:Array = [];
for (var i:int = 0; i < size; i++)
a.push( { "foo":i } );
var d:Dictionary = new Dictionary(weakKeys);
var start:int = getTimer();
var mem0:int = System.totalMemory;
for (var j:int = 0; j < size; j++)
d[a[j]] = j;
trace("adding "+size+" keys took "+(getTimer()-start)+" msecs and "+(System.totalMemory-mem0)+" B of memory with weakKeys == "+weakKeys);
}
private function benchmarkDispatchers(weakRef:Boolean, size:uint = 100000):void {
var a:Array = [];
var f:Function = function (i:*):Function {
return function ():void { i; }
}
for (var i:int = 0; i < size; i++)
a.push( f(i) );
var e:EventDispatcher = new EventDispatcher();
var start:int = getTimer();
var mem0:uint = System.totalMemory;
for (var j:int = 0; j < size; j++)
e.addEventListener("foo", a[j], false, 0, weakRef);
trace("adding " + size + " event handlers took " + (getTimer() - start) + " msecs and " + (System.totalMemory - mem0) + " B of memory with weakKeys == " + weakRef);
}
}
}
这就是我在机器上得到的东西:
adding 100000 event handlers took 679 msecs and 6922240 B of memory with weakKeys == false
adding 100000 event handlers took 1348 msecs and 13606912 B of memory with weakKeys == true
adding 1000000 keys took 283 msecs and 16781312 B of memory with weakKeys == false
adding 1000000 keys took 906 msecs and 42164224 B of memory with weakKeys == true
结果对于字典来说有点激烈,很可能是因为没有涉及时间的ActionScript调用,并且因为事件处理程序注册中的一些存储开销减少了所需内存之间的差异(如您所见,它是69字节/处理程序和16字节/键,比较弱引用时)...
所以是的,这是关于性能...使用弱引用并不是关于一个很酷的事实,你不必删除监听器以便对象死...如果你想要一个可扩展的应用程序,你需要自己做这些事情,如果你想让它100%可靠,你不能希望GC能够完成你的工作,但是你需要自己做清理...而且,如果你的应用程序中有一个良好的层次结构,你可能不会经常遇到这个问题 ......从某种意义上说,如果你不想花时间做适当的对象,这是一种奢侈清理,因为没有弱引用就无法解决的问题很少见......当它提供真正的优势时应该使用它,而不仅仅是出于懒惰......我认为这就是为什么它默认是假的......
希望有帮助......;)
格尔茨
back2dos
答案 1 :(得分:2)
你是对的,通常你确实想要使用弱引用,可能大约99%的时间。我认为默认值确实应该设置为true,但我们必须处理它不是这样。我建议你养成总是使用弱引用的习惯,你会省去一些麻烦,并看到一些性能上的好处,因为它有助于垃圾收集管理。
那么你什么时候想要它是假的?基本上,当垃圾收集器决定你不再使用时,你不希望事情自动清理。这些情况很少见,到时候你可能只知道。
HOWEVER 这可能无法解决您自己的特定问题。垃圾收集器仅以不可预测的间隔运行,因此即使您删除对对象的所有引用,它仍然可以处理这些事件,直到它被清除。您最好的选择是自己删除事件监听器,以确保它们不会再被触发。您可以使用removeEventListener方法执行此操作。
祝你好运,泰勒。
答案 2 :(得分:2)
在执行异步操作时,弱引用可能会让你感到困惑,因为任何未执行以阻止对象图执行的操作都可以随时进行垃圾回收。
特别是,永远不要对作为作用域函数的事件处理程序使用弱引用:
function weakRefSample() : void
{
var evntDispatcher : IEventDispatcher = new EventDispatcher();
evntDispatcher.addEventListener(Event.COMPLETE, scopeHandler, false, 0, true);
function scopedHandler(event : Event) : void
{
}
}
上面的例子中有两件事出了问题:
答案 3 :(得分:0)
我发现具有弱引用事件侦听器的Timer实例有时不会触发事件。