18
function(foo, cb) {
  var bigObject = new BigObject();
  doFoo(foo, function(e) {
     if (e.type === bigObject.type) {
          cb();
          // bigObject = null;
     }
  });
}

上記の例は、古典的な偶発的な (またはそうでない可能性がある) メモリ リーク クロージャを示しています。V8 ガベージ コレクターは、bigObject複数回呼び出すことができるコールバック関数で使用されているため、安全に削除できるかどうかを判断できません。

1 つの解決策は、コールバック関数でジョブが終了したときにを設定bigObjectすることです。nullしかし、多くの変数を使用している場合 ( のnような変数がbigObjectあり、それらはすべてコールバックで使用されていると想像してください)、これをきれいにするのは厄介な問題になります。

私の質問はこれです: これらの使用済み変数をきれいにする他の方法はありますか?

EDIT別の (実世界の) 例を次に示します。mongodb からアプリケーションを取得し、それを他のアプリケーションと比較します。mongodb からのコールバックは、そのコールバックから定義された変数アプリケーションを使用します。mongodb から結果を取得した後、それをコールバックとしても返します (すべて非同期であり、単に return を書くことができないため)。したがって、実際には、コールバックをソースまで伝播することが起こります...

function compareApplications(application, condition, callback) {

    var model = database.getModel('Application');
    model.find(condition, function (err, applicationFromMongo) {
        var result = (applicationFromMongo.applicationID == application.applicationID)
        callback(result)        
    }
}
4

2 に答える 2

2

コールバック関数が 1 回だけ呼び出されることになっている場合は、呼び出された後にサブスクライブを解除する必要があります。これにより、コールバック + クロージャが GC に解放されます。閉鎖bigObjectが解除されると、GC によって自由に収集されます。

これが最善の解決策です。ご指摘のとおり、GC は、コールバックが 1 回だけ呼び出されることを魔法のように認識していません。

于 2013-05-08T13:40:58.077 に答える
0

ブランドンの答えに基づいて構築するには: (何らかのひどい理由で) コールバックのサブスクライブを解除できない場合は、いつでも自分でコールバックの削除を処理できます。

function createSingleUseCallback(callback)
{
    function callbackWrapper()
    {
        var ret = callback.apply(this, arguments);
        delete callback;
        return ret;
    }
    return callbackWrapper;
}

function compareApplications(application, condition, callback)
{
    var model = database.getModel('Application');
    model.find(condition, createSingleUseCallback(function (err, applicationFromMongo)
    {
        var result = (applicationFromMongo.applicationID == application.applicationID);
        callback(result);
    })
}
于 2015-03-31T16:12:27.427 に答える