2011-05-05 70 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偵聽器和事件調度程序無法相互連接的問題。需要注意的一個重要問題是創建一個對象,該對象等待(偵聽)在初始化時已經調度的對象,因此它錯過了調用(派發事件)並且無限期掛起。

如果你的計時器顯示在調試器變量中,當它應該是滴答作響和完成時,你應該是金色的。

相關問題