所以我有一个类似的定时器:
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();
}
我需要确保someBigThing是垃圾收集的。
我的谷歌搜索结果一直告诉我,如果一个计时器永远不会停止,它将永远不会被收集,但那些停止的会怎么样?
而且我相当确定只将字段设置为null并不一定允许收集;如果我有这个:
public function doThingLater():void {
//initialize timer...
timer.start();
timer = null;
}
我仍然希望计时器能够运行。
我知道可以确保通过在Timer上调用removeEventListener来收集它,但是监听器是匿名的;显然我可以做这个工作,但我认为匿名听众更具可读性。
答案 0 :(得分:0)
是的,所以我做了一些实验,看看我能找到什么,我的代码如下。我不是100%肯定这一点,但我的主要发现点是:
在实验中,我也得出了其他一些不太相关的结论:
System.gc()
强制执行匿名函数可能会保留对对象的意外引用,因此函数从
返回function foo():Function {
var thing:Object;
//initialize thing
//Do a bunch of other stuff.
return function():void { /*do nothing*/ };
}
阻止thing
被垃圾收集。
匿名函数引用原始局部变量,所以
var thing:SomeClass;
var function:Function = function():void {
thing.doAThing();
};
//do some stuff
thing = null;
如果使用function
,将导致空引用错误。
我会等几天,看看是否有人对计时器的收集方式有充分了解,然后接受我自己的答案。无论如何,这是测试代码:
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);
}
}
}
我粘贴了它,所以如果你自己测试就要小心格式化问题。 输出是:
在发布引用之前,未收集以下对象:控制,不停止,不停止对象,删除侦听器,删除侦听器对象,停止,停止对象,事物,使用弱侦听器,使用弱侦听器对象,< / p>
释放引用后,未收集以下对象:控制,不停止,不停止对象,删除侦听器,删除侦听器对象,停止,停止对象,事物,使用弱侦听器,使用弱侦听器对象,< / p>
在Timer完成之前,尚未收集以下对象:不停止,不停止对象,删除侦听器,删除侦听器对象,停止,停止对象,事物,使用弱侦听器,
Timer完成后,未收集以下对象:不停止,不停止对象,删除侦听器,删除侦听器对象,停止,停止对象,事物,使用弱侦听器,
在Timer完成后,以下对象尚未收集:不停止,不停止对象,事物,
按键时,未收集以下对象:不停止,不停止对象,事物,