假设1。我有一个名为Experiment
的实用工具类。它有助于在选定的精灵上侦听EnterFrame事件。 API看起来如下:Experiment.listenEnterFrame(mySprite, onEnterFrameHandler);
。
假设2。我希望我的Experiment.listenEnterFrame
类允许使用匿名处理程序。我还希望它具有内存泄漏能力(没有任何cleanUp()
方法),即对mySprite的引用应该很弱。
以下是代码:
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.System;
import flash.utils.Dictionary;
import flash.utils.setTimeout;
public class Experiment extends Sprite
{
public function Experiment()
{
new MemoryLeakTest();
new NoMemoryLeakTest();
setTimeout(System.gc, 100);
}
private static var dict:Dictionary = new Dictionary(true);
private static function listener(event:Event)
{
dict[event.currentTarget]();
};
public static function listenEnterFrame(dispatcher:Sprite, callback:Function):void
{
dict[dispatcher] = callback;
dispatcher.addEventListener(Event.ENTER_FRAME, listener, false, 0, true);
}
}
}
import flash.display.Sprite;
internal class MemoryLeakTest extends Sprite
{
function MemoryLeakTest():void
{
Experiment.listenEnterFrame(this, function () {
trace("Memory leak");
});
}
}
internal class NoMemoryLeakTest
{
function NoMemoryLeakTest():void
{
Experiment.listenEnterFrame(new Sprite(), function () {
trace("No Memory leak");
});
}
}
在上面的示例中,永远不会删除MemoryLeakTest实例 - 永远跟踪“内存泄漏”。
我对此的解释是callback
中创建的MemoryLeakTest
闭包会引用外部作用域,即MemoryLeakTest
实例本身。由于此引用,MemoryLeakTest
实例无法进行垃圾回收。
你知道任何解决方法,所以我可以在我的实用工具方法中使用匿名回调而不必担心内存释放吗?
答案 0 :(得分:1)
在AS3中有一个已知的词典错误。而不是存储对函数/方法的引用,而是存储对闭包对象的引用。
这意味着如果您希望将函数引用存储为字典中的键,如果Dictionary使用弱键,则会立即将其标记为GC,因为Dictionary引用了闭包对象而不是函数本身。
这也意味着如果您尝试将函数引用存储为Dictionary中的值,那么只要Dictionary保持闭包,闭包对象引用的实例就不会是GC'd宾语。 (字典有弱键而不是值!) 这正是这里发生的事情。