Actionscript 3 已完成、未引用计时器的垃圾收集

Actionscript 3 已完成、未引用计时器的垃圾收集,actionscript-3,timer,garbage-collection,Actionscript 3,Timer,Garbage Collection,我有一个计时器,比如: private var timer:Timer; public function doThingLater():void { timer = new Timer(1000, 1); var someBigThing:SomeBigThing = new SomeBigThing(); timer.addEventListener(TimerEvent.TIMER_COMPLETE, function():void { some

我有一个计时器,比如:

private var timer:Timer;

public function doThingLater():void {
    timer = new Timer(1000, 1);

    var someBigThing:SomeBigThing = new SomeBigThing();

    timer.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
        someBigThing.doThing();
        timer = null;
    });
    timer.start();
}
我需要确定有什么东西是垃圾收集的

我的谷歌搜索结果一直告诉我,如果计时器从未停止,它将永远不会被收集,但那些停止的计时器呢

我相当肯定,仅仅将字段设置为null并不一定允许收集;如果我有这个:

public function doThingLater():void {
    //initialize timer...
    timer.start();
    timer = null;
}
我仍然希望计时器运行


我知道可以通过在计时器上调用removeEventListener来确保它被收集,但是侦听器是匿名的;显然我可以做到这一点,但我认为匿名侦听器更具可读性。

对,所以我做了一些实验,看看能找到什么,我的代码如下。我对这些都不是100%肯定,但我的主要发现是:

  • 是的,停止的计时器最终将被收集
  • 删除侦听器也同样有效
  • 使用弱引用的监听器也可以,只要对监听器的另一个引用保持到不再需要为止
在实验中,我还得出了其他一些不太相关的结论:

  • 垃圾收集何时起作用很难预测,即使是使用
    System.gc()
  • 匿名函数复制当前函数的整个激活记录,这导致了另外两个令人不安的结论:
  • 匿名函数可能包含对对象的意外引用,因此从

    function foo():Function {
        var thing:Object;
        //initialize thing
    
        //Do a bunch of other stuff.
    
        return function():void { /*do nothing*/ };
    }
    
    阻止
    对象被垃圾收集

  • 匿名函数引用原始局部变量,因此

    var thing:SomeClass;
    
    var function:Function = function():void {
        thing.doAThing();
    };
    
    //do some stuff
    
    thing = null;
    
    如果使用了
    函数
    ,将导致空引用错误

我会等几天,看看是否有人对计时器是如何收集的有深入的了解,然后接受我自己的答案。无论如何,下面是测试代码:

package 
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.TimerEvent;
    import flash.system.System;

    import flash.utils.Dictionary;
    import flash.utils.Timer;

    public class Main extends Sprite 
    {
        public static var objects:Dictionary;

        private var control:Vector.<int>;

        private var doesNotStop:Timer;
        private var stops:Timer;
        private var removesListener:Timer;
        private var usesWeakListener:Timer;

        private static var before:Timer, after:Timer;

        private static var beforeTime:Number = 100;
        private static var time:Number = 1000;
        private static var afterTime:Number = 2000;
        private static var wellAfterTime:Number = 6000;

        public function Main():void 
        {
            if (stage) init(null);
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
        public function init(event:Event):void {
            doIt();

            printObjects("After releasing references, ");

            stage.addEventListener(KeyboardEvent.KEY_DOWN, test);
        }

        public function test(event:Event):void {
            printObjects("On key press, ");
        }
        public function doIt():void {

            objects = new Dictionary(true);

            //Create objects.
            var thing:Vector.<int> = createBigObject();

            control = createBigObject();

            var stopsObject:Object = initializeStops();

            var doesNotStopObject:Object = initializeDoesNotStop();

            var removesListenerObject:Object = initializeRemovesListener();

            var usesWeakListenerObject:Object = initializeUsesWeakListener();

            //Add them to the dictionary.
            objects[control] = "control";

            objects[thing] = "thing";

            objects[doesNotStop] = "does not stop";
            objects[doesNotStopObject] = "does not stop object";

            objects[stops] = "stops";
            objects[stopsObject] = "stops object";


            objects[removesListener] = "removes listener";
            objects[removesListenerObject] = "removes listener object";

            objects[usesWeakListener] = "uses weak listener";
            objects[usesWeakListenerObject] = "uses weak listener object";

            printObjects("Before releasing references, ");

            //Release local references.
            control = null;

            doesNotStop = null;
            doesNotStopObject = null;

            stops = null;
            stopsObject = null;

            removesListener = null;
            removesListenerObject = null;

            usesWeakListener = null;
            usesWeakListenerObject = null;


            //Start timers to check gc later.
            before = new Timer(beforeTime, 1);
            var listener:Function =  function():void {
                printObjects("Before the Timer has finished, ");
            };
            before.addEventListener(TimerEvent.TIMER_COMPLETE, listener, false, 0, false);
            before.start();

            after = new Timer(afterTime, 1);
            after.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
                printObjects("After the Timer has finished, ");
            });
            after.start();

            var wellAfter:Timer = new Timer(wellAfterTime, 1);
            wellAfter.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
                printObjects("Well after the Timer has finished, ");
            });
            wellAfter.start();
        }

        private function initializeDoesNotStop():Object {
            var object:Vector.<int> = createBigObject();

            doesNotStop = new Timer(time, 0);
            doesNotStop.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
                object[0] = 10;
            });
            doesNotStop.start();

            return object;
        }

        private function initializeStops():Object {
            var object:Vector.<int> = createBigObject();

            stops = new Timer(time, 1);
            stops.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
                object[0] = 10;
            });
            stops.start();

            return object;
        }

        private function initializeRemovesListener():Object {
            var object:Vector.<int> = createBigObject();

            var listener:Function = function(event:Event):void {
                object[0] = 10;
                (event.target as Timer).removeEventListener(TimerEvent.TIMER_COMPLETE, listener);
            };

            removesListener = new Timer(time, 1);
            removesListener.addEventListener(TimerEvent.TIMER_COMPLETE, listener);
            removesListener.start();

            return object;
        }

        private function initializeUsesWeakListener():Object {
            var object:Vector.<int> = createBigObject();

            usesWeakListener = new Timer(time, 1);
            usesWeakListener.addEventListener(TimerEvent.TIMER_COMPLETE, function():void {
                object[0] = 10;
            }, false, 0, true);
            usesWeakListener.start();

            return object;
        }

        public static function createBigObject():Vector.<int> {
            var out:Vector.<int> = new Vector.<int>(100, true);
            for (var i:int = 0; i < 100; i++)
                out[i] = i;

            return out;
        }

        public static function printObjects(msg:String):void {

            System.gc();

            var output:String = msg + "the following objects have not been collected: ";

            var objectNames:Vector.<String> = new Vector.<String>();

            for each (var value:String in objects) {
                objectNames.push(value);
            }

            objectNames.sort(0);

            for each (var str:String in objectNames) {
                output += str + ", ";
            }

            trace(output);
        }

    }

}
包
{
导入flash.display.Sprite;
导入flash.events.Event;
导入flash.events.KeyboardEvent;
导入flash.events.TimerEvent;
导入flash.system.system;
导入flash.utils.Dictionary;
导入flash.utils.Timer;
公共类Main扩展了Sprite
{
公共静态var对象:字典;
私有var控制:向量。;
私有变量不停止:计时器;
私有变量停止:定时器;
私有var removesListener:计时器;
私有变量useSwakListener:计时器;
私有静态变量before:Timer,after:Timer;
私有静态变量beforeTime:Number=100;
私有静态变量时间:Number=1000;
私有静态变量后时间:Number=2000;
私有静态var WellAfterime:Number=6000;
公共函数Main():void
{
if(stage)init(null);
其他的
addEventListener(Event.ADDED_TO_STAGE,init);
}
公共函数初始化(事件:事件):无效{
doIt();
printObjects(“发布引用后,”);
stage.addEventListener(KeyboardEvent.KEY_DOWN,test);
}
公共功能测试(事件:事件):无效{
printObjects(“按键时,”);
}
公共函数doIt():void{
objects=新字典(true);
//创建对象。
变量thing:Vector.=createBigObject();
control=createBigObject();
var stopsObject:Object=initializeStops();
var doesnotstobject:Object=initializedesnotstop();
var removesListenerObject:Object=initializeRemovesListener();
var useSwakListenerObject:Object=InitializeUserWeakListener();
//将它们添加到字典中。
对象[控制]=“控制”;
对象[事物]=“事物”;
对象[doesNotStop]=“不停止”;
对象[doesNotStopObject]=“不停止对象”;
对象[停止]=“停止”;
对象[停止对象]=“停止对象”;
对象[removesListener]=“删除侦听器”;
对象[RemoveListenerObject]=“删除侦听器对象”;
对象[UseSwakListener]=“使用弱侦听器”;
对象[UseSwakListenerObject]=“使用弱侦听器对象”;
printObjects(“在发布引用之前,”);
//发布本地引用。
控制=空;
doesNotStop=null;
doesNotStopObject=null;
停止=空;
stopsObject=null;
removesListener=null;
RemoveListenerObject=null;
UseSwakListener=null;
UseSwakListenerObject=null;
//启动计时器以稍后检查gc。
before=新计时器(beforeTime,1);
变量侦听器:Function=Function():void{
printObjects(“在计时器完成之前,”);
};
before.addEventListener(TimerEvent.TIMER\u COMPLETE,listener,false,0,false);
before.start();
after=新计时器(after Time,1);
在.addEventListener(TimerEvent.TIMER_完成后,函数():void{
printObjects(“计时器完成后,”);
});
在.start()之后;
var wellAfter:计时器=新计时器(wellAfterTime,1);
wellAfter.addEventListener(TimerEvent.TIMER_完成,函数():void{
printObjects(“在计时器完成之后,”);
});
wellAfter.start();
}
私有函数initializedesnotstop():对象{
变量对象:Vector.=createBigObject();
doesNotStop=新计时器(时间,0);
doesNotStop.addEventListener(TimerEvent.TIMER_完成,函数():void{
对象[0]=10;
});
doesNotStop.start();
返回对象;
}
私有函数initializeStops():对象{