如何使封闭外部范围参考较弱。或任何其他解决方法

时间:2012-08-07 10:07:40

标签: actionscript-3 flex

假设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实例无法进行垃圾回收。

你知道任何解决方法,所以我可以在我的实用工具方法中使用匿名回调而不必担心内存释放吗?

1 个答案:

答案 0 :(得分:1)

在AS3中有一个已知的词典错误。而不是存储对函数/方法的引用,而是存储对闭包对象的引用。

这意味着如果您希望将函数引用存储为字典中的,如果Dictionary使用弱键,则会立即将其标记为GC,因为Dictionary引用了闭包对象而不是函数本身。

这也意味着如果您尝试将函数引用存储为Dictionary中的,那么只要Dictionary保持闭包,闭包对象引用的实例就不会是GC'd宾语。 (字典有弱而不是值!) 这正是这里发生的事情。