IE で メモリ を 強制的 に 解放

0 件のコメント

メモリーリークに近い話とは思いますが、ちょっと毛色の違う内容です。 「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 を設定しても即時解放はされません。 ちなみに、 nulldelete も同じく即時解放されません。

最後になりましたが… 上記サンプル HTML を IE8 以上で window.open し、setup ボタン押下後、ウィンドウを閉じる、window.openし、setup ボタン押下後、… を繰り返すと、メモリリークという形で残る場合が見られます。 メモリリークさせるコツは window.open で、ダイアログ表示させる(オプションで toolbar=no とか行う)とか…? window.CollectGarbage() を行えば、"ある程度"メモリリークは防げそうです。