メモリーリークに近い話とは思いますが、ちょっと毛色の違う内容です。 「JavaScript がメモリーを馬鹿食いしてどうしようもない…」 「なぜかメモリーが確保されっぱなしなんだけど…?」 といった状況の解消法。
JavaScript にはガーベッジコレクタがあるから大丈夫… と、思われがちですが、ガーベッジコレクタは『本当にメモリ解放が必要になるまで何もしない』というものです。 (状況が悪いとガーベッジコレクタは何もしてくれなくて、ブラウザが固まってしまいます。。)
「コストはかかるが、信用できないならプログラマが勝手にやってしまえ!!」という感じです。
削除候補のメモリを強制解放 ── CollectGarbage() 関数 ──
解放したいタイミングで window.CollectGarbage() を走らせることで、強制的にメモリを解放できます。
// IE 以外のブラウザ対策のため、関数の存在をチェック
if (window.CollectGarbage) {
window.CollectGarbage();
}
この CollectGarbage 関数に関する詳細は、MSDN をご参照ください。
メモリー解放されないコード と その解放
IE で DOM要素 を動的生成した場合、メモリが確保されたままになることがあります。
以下のサンプルでは、 setup_onclick によってメモリを確保し、
teardown_onclick によって強制的に解放します。
テスト用 HTML
<html>
<head>
<script type="text/javascript">
/**
* setup ボタン 押下時の処理
*/
var setup_onclick = function (event) {
var i, elem, frag;
// DOM要素 を大量に生成する…だけ。
frag = document.createDocumentFragment();
for (i = 0; i < 5000; i++) {
elem = document.createElement('div');
frag.appendChild(element);
}
// 一般的に「解放される」と言われているコード
elem = frag = undefined;
};
/**
* teardown ボタン 押下時の処理
*/
var teardown_onclick = function (event) {
if (window.CollectGarbage) {
window.CollectGarbage();
}
};
var window_onload = function () {
document.getElementById('setup').onclick = setup_onclick;
document.getElementById('teardown').onclick = teardown_onclick;
};
window.onload = window_onload;
</script>
</head>
<body>
<input type="button" id="setup" value="setup leak" />
<input type="button" id="teardown" value="teardown leak" />
</body>
</html>
上記サンプルコード を IE9 で実行した状況を ProcessExplorer で監視した結果
上図グラフの立ち上がりは setup leak ボタンを押下(setup_onclick を実行)したタイミングで、
グラフの立ち下がりは teardown ボタンを押下(teardown_onclick を を実行)したタイミングです。
台形の間の時間は約1分(1分以上)です。
少なからず、1分程度では undefined を設定しても即時解放はされません。
ちなみに、 null、delete も同じく即時解放されません。
最後になりましたが…
上記サンプル HTML を IE8 以上で window.open し、setup ボタン押下後、ウィンドウを閉じる、window.openし、setup ボタン押下後、…
を繰り返すと、メモリリークという形で残る場合が見られます。
メモリリークさせるコツは window.open で、ダイアログ表示させる(オプションで toolbar=no とか行う)とか…?
window.CollectGarbage() を行えば、"ある程度"メモリリークは防げそうです。
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!
