2016-07-09 9 views
0

簡単な質問ですが、私はまだ100%確信しているという回答は見つかりませんでした。ループ内のJavascript関数の割り当てガベージ作成

バージョン1:

var a = [1,2,3]; 
function doStuff(obj) { 
    //do nothing 
} 
function test() { 
    a.forEach(doStuff); 
} 
setInterval(test, 1000/60); 

バージョン2:

var a = [1,2,3]; 
function test() { 
    a.forEach(function(obj) { 
     //do nothing 
    }); 
} 
setInterval(test, 1000/60); 

バージョン1は、2つの機能を割り当て、これまでに何かを割り当てません。このコードは考えてみましょう。

バージョン2は、test()が呼び出されるたびに新しい関数を割り当てますか?私は、 test()が呼び出されるたびに、バージョン2のforEach内部の無名関数がで作成されることを理解していますが、test()の呼び出しが終了すると、それ以上参照がなく、ガベージコレクションが可能です。したがって、バージョン2を長時間実行すると、ガベージコレクタは、作成されたガベージオブジェクトバージョン2をクリーンアップする必要があります。私は正しい?

+1

実際にテストを毎秒6万回呼び出すことを意味しましたか?ブラウザはその要求を尊重しないためです。 –

+0

はい、バージョン2は 'test'が呼び出されるたびに新しい関数オブジェクトをインスタンス化しますが、実行する必要のある(ヒープ)ガーベジコレクションなしでスタックに割り当てることができるかもしれません。 – Bergi

+0

ES3は2番目の機能をリサイクルすることを許可しましたが、後のコアでもそのように最適化されず、機能の起動部分以外のすべてを再使用することは想像できません。 – dandavis

答えて

0

引数を保存して関数が等しいかどうかをテストすることで、これをテストできます。

var saved = []; 
 

 
function saveIt(fun) { 
 
    saved.push(fun); 
 
} 
 

 
function test() { 
 
    saveIt(function(obj) { 
 
    // do nothing 
 
    }); 
 
} 
 

 
test(); 
 
test(); 
 
console.log(saved[0] === saved[1]);

私はChromeでこれを実行すると、それはfalseをログに記録しますので、2つの機能は確かに異なっています。

しかし、その違いは関数のコード部分ではなく、クロージャのコンテキスト内である可能性があります。まともなコンパイラは、これを呼び出すたびに無名関数に同じコードを使用し、すべてのクロージャが参照する共通オブジェクトにそのコードを抽出することができるはずです。

さらにスマートなコンパイラでは、この関数は決して自由変数を参照しないので、字句コンテキストを使用する必要はありません。したがって、それを使用するたびに同等でなければならず、いつでも再利用できます。しかし、明らかにChromeコンパイラはそれほど巧妙ではありません。

+0

他のウェブブラウザが同じ任意の選択をすることを単に信じるだけではありません;-) –

+0

"*しかし、明らかにChromeコンパイラはそれほど巧妙ではありません。*" - あなたはどのように知っていますか?要点は、この最適化は、観測できない場合にのみ可能であるということです。 – Bergi

+0

'test()'をコンパイルするときに、 'saveIt()'がその違いを見えるようにする関数で何かを実行してから最適化を省略するかどうかを確認することをお勧めしますか? – Barmar

関連する問題