6

理解できないメモリリークがあります。メモリを簡単にクリーンアップできるように、半自動的にバインドを解除してイベントを処理するメカニズムをプログラムしました。しかし、1 つのケースでは、クリーンアップが行われません (私はクロムの「プロファイル (メモリ ヒープ)」を使用して、「EventHandler」のインスタンスが残っているかどうかを確認します)。なぜそれが起こるのか本当にわかりません。締め方がなんかおかしい…

クロムでの動作を確認してください

function Bind(obj, f) {
    return function() {
        return f.apply(obj, arguments);
    }
}

function EventHandler() {
    this.listeners = new Object();

    var _listenerID = 0;
    this.addListener = function(e, obj, listener, specialDisplay) {
        if (typeof(listener) === "function") {
            var listenerID = ++_listenerID;
            console.log("Events (" + (++EventHandler.All) + ", " + listenerID + ") ++" + e);

            if (!this.listeners.hasOwnProperty(e)) {
                this.listeners[e] = new Object();
            }
            this.listeners[e][listenerID] = listener;

            if (obj != null && typeof(obj.removeListener) == "function") {
                var deleteListenerID = obj.addListener("Delete", null, Bind(this, function() {
                    this.removeListener(e, listenerID);
                    obj.removeListener("Delete", deleteListenerID);
                }));
            }

            return listenerID;
        }

        return null;
    }
    this.fire = function(e, obj) {
        if (this.listeners.hasOwnProperty(e)) {
            for(var i in this.listeners[e]) {
                this.listeners[e][i](obj);
            }
        }
    }
    this.removeListener = function(e, listenerID) {
        if (this.listeners.hasOwnProperty(e) && this.listeners[e].hasOwnProperty(listenerID)) {
            delete this.listeners[e][listenerID];

            console.log("Events (" + (--EventHandler.All) + ", " + listenerID + ") --" + e);
        }
    }
}

EventHandler.All = 0;

function Loader() {
}

Loader.files = new Object();

Loader.LoadImage = function(src, f) {
    if (!Loader.files.hasOwnProperty(src)) {
        var handler = new EventHandler();

        console.log("Loading.... (" + src + ")");

        Loader.files[src] = function(fnct) {
            handler.addListener("ImageLoaded", handler, function(img) {
                fnct(img);
            });
        }

        handler.addListener("ImageLoaded", handler, function() {
            Loader.files[src] = function(fnct) {
                fnct(img);
            }
        });     

        var img = new Image();
        $(img).load(function() {
            console.log("Loaded.... (" + src + ")");
            handler.fire("ImageLoaded", img);
            handler.fire("Delete");
            $(img).unbind('load');
        });
        img.src = src;
    }

    Loader.files[src](f);
}

Loader.LoadImage("http://serge.snakeman.be/Demo/house.jpg", function() { alert("ok"); });
4

2 に答える 2

2

変数EventHandlerを介してインスタンスへの参照を保持するクロージャーを作成します。handler画像がロードされた後、クロージャーの 1 つが残ります。

    handler.addListener("ImageLoaded", handler, function() {
        Loader.files[src] = function(fnct) {
            fnct(img);
        }
    });     

内部関数function(fnct) {...です。EventHandlerクロージャが存在する限り、のインスタンスを解放することはできません。あなたの唯一の解決策は、その閉鎖を取り除くことです。または、可能であればインスタンスを手動で解放します。以下はあなたのために働くかもしれません:

handler.fire("Delete");
handler = undefined;

Chrome のメモリ プロファイラは、オブジェクトの保持ツリーを表示します。これは、「そのオブジェクトの参照を保持しているのは誰か」という別の言い方です。あなたの例では、それはEventHandler <- handler (クロージャによって組み込まれた LoadImage メソッドの変数) <- house.jpgであり、実際にはLoader.files[src]値があり、値を持っていますfunction(fnct) { fnct(img); }

于 2013-04-21T16:27:31.087 に答える
2

「リスナー」を追加している間、クエリを長時間使用している場合は、それを削除していることを確認してください。

this.listeners = new Object();

また

this.listeners[e] = new Object();

これにより、オブジェクトが配列としてリスナーに追加されますが、どの時点でも削除されません。

これがメモリ消費の原因である可能性があります。オブジェクトの割り当てが漏れることはありません。ブラウザを使用してRAMを消費します。:)

于 2013-04-23T06:58:58.350 に答える