Javascript ライブラリのテスト中に、IE10 (v10.0.9200.16519 - Windows 8 64 ビット) の Javascript 実装で重大なメモリ リークが見つかったと思いますsetInterval
。
簡単なテスト ケースでは、後で実行するための引数として渡される関数のクロージャで変数がキャプチャされた場合、ガベージ コレクションの対象になることはないようです。つまり、ブラウザは依然として関数への参照を保持しているように見えます。少なくとも閉鎖変数。
テストケースは関数を 1 回だけ実行しsetInterval
、インターバル タイマーをクリアします。つまり、しばらくすると、コードが実行されなくなり、変数にアクセスできなくなります (実行するメソッドを除いて、このコードにはグローバルが導入されていないことがわかります)。でonload
)、それにもかかわらず、プロセスは(反復回数に応じて)0.5ギガバイトのメモリを消費します。
興味深いことに、setTimeout
代わりにメソッドを使用すると、これは発生しません (また、問題はIE9 および Chrome の現在のバージョン、FF には存在しないようです)。
問題は、この fiddleで見ることができます。
Windows 8 の IE10 の新しいインスタンスで実行し、タスク マネージャーを開いてメモリ使用量を監視します。すぐに 350 メガバイトまで大きくなり、スクリプトが実行された後もそこにとどまります。
これは、問題のあるコード部分の重要な部分です。
// the function that when called multiple times will cause the leak in IE10
var eatMemory = function() {
var a = null; // the captured closure variable
var intervalId = setInterval(function() {
a = createBigArray(); // call a method that allocates a lot of memory
clearInterval(intervalId); // stop the interval timer
}, 100);
}
(この特定のコードを簡単に修正できることはわかっています。しかし、それは問題ではありません。これは、問題を再現するために私たちが思いついた最も小さなコードにすぎません。実際のコードは実際this
にクロージャーでキャプチャされ、そのオブジェクトはガベージ コレクションは行われません。)
私たちのコードにバグがありますか、それともsetInterval
クロージャ変数が大きなオブジェクトへの参照を保持する場合に、メモリ リークを引き起こさずに、また「再帰的」setTimeout
呼び出しに戻らずに使用する方法はありますか?
更新:この問題は Windows 7 の IE10 でも発生しますが、IE9 標準モードに切り替えると発生しません。これを MS Connect に送信しました。進捗状況を報告します。
更新: Microsoftはこの問題を受け入れ、 IE11 (プレビュー バージョン) で修正されると報告しました - 私自身はまだ確認していません (誰か?)
更新: IE 11 が正式にリリースされましたが、私のシステム (Win 8.1 Pro 64 ビット) でそのバージョンの問題を再現できなくなりました。