1

假设 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实例不能被垃圾收集。

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

4

1 回答 1

1

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

这意味着如果您想将函数引用作为存储在 Dictionary 中,如果 Dictionary 使用弱键,它将立即被标记为 GC,因为 Dictionary 引用的是闭包对象而不是函数本身。

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

于 2012-08-07T13:49:27.557 回答