2011-05-05 64 views
5

我有一类函数下面的代码:本地计时器对象的事件处理程序

public function foo():void 
{ 
    var timer:Timer = new Timer(10000,1); 
    timer.addEventListener(TimerEvent.TIMER_COMPLETE,onTimerComplete); 
    timer.start(); 
} 

public function onTimerComplete(e:TimerEvent):void 
{ 
    // do stuff 
} 

上面的代码工作的大部分时间,但我关心的是,如果计时器被垃圾回收会发生什么?有没有可能onTimerComplete永远不会触发,因为没有其他引用计时器?

我知道计时器有一个处理程序的内部列表,但不会阻止它被GC'ed。

回答

1

有在网络上运行的计时器绝不被垃圾收集,e.g.一些参考:

只是要清楚:即使你有一个计时器的引用,只要 作为定时器运行,它不会被垃圾收集(想想 它就好像运行时保持对运行定时器的引用)。

由阿诺Gourdol在Adobe AIR团队

,但我一直没能找到一个权威来源。

尽管如此,最好不要依赖这种特殊行为,而应该使timer成为一个类级变量。

解决方案建议事件监听器保持计时器不被垃圾回收不正确。引用是从定时器到侦听器函数(onTimerComplete),所以如果定时器可到达,那么侦听器函数将不会被垃圾收集,但反之亦然。这很容易测试:

<?xml version="1.0" encoding="utf-8"?> 
<s:Application 
xmlns:s="library://ns.adobe.com/flex/spark" 
creationComplete="application1_creationCompleteHandler(event)"> 

<fx:Script> 
    <![CDATA[ 
private var _gcTimer:Timer; 

protected function application1_creationCompleteHandler(event:FlexEvent):void { 
    var timer:Timer = new Timer(30, 4); 
    timer.addEventListener(TimerEvent.TIMER, onTimer, false, 0, true); 

    var sprite:Sprite = new Sprite(); 
    sprite.addEventListener(Event.ENTER_FRAME, onSprite, false, 0, true); 

    _gcTimer = new Timer(59, 1); 
    _gcTimer.addEventListener(TimerEvent.TIMER, garbageCollect); 

    timer.start(); 
    _gcTimer.start(); 
} 

private function onTimer(event:TimerEvent):void { 
    trace("timer"); 
} 

private function onSprite(event:Event):void { 
    trace("sprite"); 
} 
]]> 
</fx:Script> 
</s:Application> 

输出:

精灵
计时器
精灵
计时器
收集垃圾
计时器
计时器

0

如果你关心的是垃圾收集,你可以把计时器放到一个数组中以便参考吗?

var antiGarbage:Array = []; 
var timer:Timer = new Timer(10000, 1); 

antiGarbage[antiGarbage.length] = timer; 

我不认为有一个问题,虽然,很肯定你必须做的:

timer.removeEventListener(TimerEvent.COMPLETE, onTimerComplete); 

为使定时准备好GC。

0

基本上你的计时器正在做的是一次调用onTimerComplete方法,所以为什么要关心它是否为GCed。
无论如何,你正在玩的东西非常接近JavaScipt闭包。闭包是一个失去了它的范围的功能。当某些东西失去作用时,对它进行GC化变得非常困难,特别是因为你仍然有一个事件监听器附加在它上面。你的情况毫无意义,因为它只运行一次。
良好的编码习惯是在完成对象之后清空对象。
另外,关于你的代码还有一件事。
这是错误的。

timer.addEventListener(TimerEvent.COMPLETE,onTimerComplete); 

应该

timer.addEventListener(TimerEvent.TIMER_COMPLET,onTimerComplete); 


如果将计时器对象类范围内它不会GCed。

public var timer:Timer = new Timer(10000,1); 
public function foo():void 
{ 
    this.timer.addEventListener(TimerEvent.TIMER_COMPLETE,this.onTimerComplete); 
    this.timer.start(); 
} 

public function onTimerComplete(e:TimerEvent):void 
{ 
    // do stuff 
} 
+0

我的共同ncern是如果计时器的延迟时间过长,可以说数千秒有计时器被垃圾收集的可能性,并且onTimerComplete永远不会被调用。 – 2011-05-05 00:58:49

+0

它不应该被GCed直到事件监听器被删除。 – 2011-05-05 01:05:44

+0

你确定吗?这篇文章:http://gingerbinger.com/2010/07/actionscript-3-0-events-the-myth-of-useweakreference/指出,听众不会让调度员不被GC检查。 – 2011-05-05 01:07:14

0

我将避免antiGarbage阵列,除非你已经看到了问题,因为它增加了额外的复杂性,以应付12个月,现在神奇地解决它。

只要创建对象,我没有遇到事件AS3侦听器和事件调度程序无法相互连接的问题。需要注意的一个重要问题是创建一个对象,该对象等待(侦听)在初始化时已经调度的对象,因此它错过了调用(派发事件)并且无限期挂起。

如果你的计时器显示在调试器变量中,当它应该是滴答作响和完成时,你应该是金色的。

相关问题