I have the following code in a class function :
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
}
开发者_如何学Python
The above code works most of the time but my concern is what happens if timer gets garbage collected? Is it possible that onTimerComplete will never fire because there are no other references to timer?
I know timer has an internal list of handlers but that won't keep it from being GC'ed.
There are some references on the web to running timers never being garbage collected, e.g.:
Just to be clear: even if you have no references to a Timer, as long as the timer is running, it will not be Garbage Collected (think of it as if the runtime was keeping a reference to running timers).
by Arno Gourdol on the Adobe AIR Team
but I haven't been able to find an authoritative source.
Probably best to not rely on this special behavior and instead make timer
a class-level variable, though.
Answers suggesting that event listeners are keeping the timer from being garbage collected are incorrect. The reference is from the timer to the listener function (onTimerComplete
), so if the timer is reachable then the listener function won't be garbage collected, but not vice versa. This is easily tested:
<?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>
Output:
sprite
timer
sprite
timer
Collecting garbage
timer
timer
If your concern is garbage collection, can you just put the timer into an array to keep reference to it?
var antiGarbage:Array = [];
var timer:Timer = new Timer(10000, 1);
antiGarbage[antiGarbage.length] = timer;
I don't think there's a concern though, pretty sure you would have to do:
timer.removeEventListener(TimerEvent.COMPLETE, onTimerComplete);
For the timer to be ready for GC.
I would avoid the antiGarbage array unless you've already seen a problem and that magically solves it because it adds extra complexity to deal with 12 months from now.
I haven't had any trouble with event AS3 listeners and event dispatchers failing to connect with each other as long as objects were created. One important gotchya to watch out for is creating an object that is stuck waiting (listening) for something that was already dispatched earlier in the initialization and so it missed the call (dispatched event) and hangs indefinitely.
If your Timer shows up in the debugger variables when it is supposed to be ticking and completing then you should be golden.
Basically what your timer is doing is calling the onTimerComplete method once anyway so why care if it is GCed.
In any case you are playing with something very close to a JavaScipt closure. A closure is a function that has lost its scope. When something loses scope it becomes very hard to GC it, especially since you still have an event listener attached to it. Pointless in your case because it is only running once.
Good coding practices would be to null out the object after you are done with it.
Also, one more thing about your code.
This is wrong.
timer.addEventListener(TimerEvent.COMPLETE,onTimerComplete);
Should be
timer.addEventListener(TimerEvent.TIMER_COMPLET,onTimerComplete);
If you move the timer object to the class scope it will not be 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
}
精彩评论