web-dev-qa-db-ja.com

メモリリークを回避するためにJavaScriptでDOM要素を破棄する方法

ユーザーが特定のケースの詳細をポストバックなしで表示できるアプリケーションがあります。ユーザーがサーバーにデータを要求するたびに、次のマークアップをプルダウンします。

<form name="frmAJAX" method="post" action="Default.aspx?id=123456" id="frmAJAX">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" />
</div>
<div>
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" />
</div>
<div id="inner">
<!-- valid info here --!>
</div>
</form>

次に、上記を取得し、innerHTMLを次のような新しいDOM要素に変換します。

   success: function(xhtml) {
        var tr = document.createElement('tr');
        var td = document.createElement('td');
        var container = document.createElement('div');

        obj.parentNode.parentNode.parentNode.insertBefore(tr, obj.parentNode.parentNode.nextSibling);

        td.appendChild(container);
        container.innerHTML = xhtml;
        tr.appendChild(td);

しかし、上記の後、jQueryを使用して厄介なaspnetジャンクを削除しました

$('form:eq(1)').children().each(
    function() {
        if ($('form:eq(1)').find('div').filter(function() { return $(this).attr('id') == ''; }).remove());
    }
);

//Capture the remaining children
var children = $('form:eq(1)').children();

// Remove the form
$('form:eq(1)').remove();

// append the correct child element back to the DOM
parentObj.append(children);

私の質問はこれです- IESieve を使用しているとき、実際のリークは発生していませんが、DOM要素の数(メモリ使用量)は増え続けています。

この混乱を実際にクリーンアップするために、クライアント側で何を改善できますか?注-IE7/8は両方ともこれらの結果を示しています。

[〜#〜] edit [〜#〜]:私はようやくこれを機能させ、短い ブログ投稿 を書くことにしました=完全なソースコード付き。

28
Toran Billups

トリッキーな部分は、問題のノードへの参照がまだどこに存在するかを理解することです。

これは難しい方法です。すべてのマークアップをページに追加してから、不要なものを削除します。代わりにこのようにします:

var div = document.createElement('div');
// (Don't append it to the document.)

$(div).html(xhtml);

var stuffToKeep = $(div).find("form:eq(1)> *").filter(
  function() {
    return $(this).attr('id') !== '';
  }
);

parentObj.append(stuffToKeep);

// Then null out the original reference to the DIV to be safe.
div = null;

これがリークを止めることは保証されていませんが、良いスタートです。

12
function discardElement(element) {
    var garbageBin = document.getElementById('IELeakGarbageBin');
    if (!garbageBin) {
        garbageBin = document.createElement('DIV');
        garbageBin.id = 'IELeakGarbageBin';
        garbageBin.style.display = 'none';
        document.body.appendChild(garbageBin);
    }
    // move the element to the garbage bin 
    garbageBin.appendChild(element);
    garbageBin.innerHTML = '';
}

ソース

7
David Driver

remove()とそのilkは、DOMから要素を削除するだけです。彼らはまだどこかに記憶に残っています。

これは、AJAXおよびWeb 2.0の既知の問題です。サイトを設計する以外に、ページを更新して物事を一掃することを確実にすること以外にできることはほとんどありません。

2
Randolpho

「常に増大するメモリ消費量」は多少誤解されていると思います。それはあなたのJSコードで行う必要があるよりも、ブラウザ内(そして一般的にはWindowsでも)のメモリ管理に関係しています。メモリマネージャーは通常、必要になるまで割り当てを続けます(または解放を避けます)。ページファイルとメモリマッピングに基づくシステムでは、メモリの割り当てと解放に非常に時間がかかります。

したがって、ノードが実際のドキュメント構造とDOMから解放されている場合でも、「リアルタイム」でWindows自体からノードを測​​定する方法はほとんどありません。

これを試して:

  1. タスクマネージャーを起動し、プロセスタブに切り替えて、ブラウザのメモリを監視します

  2. 100.000ノードを割り当てるHTMLドキュメントを読み込み、メモリ消費の増加を監視します

  3. すべてのノードを解放するページのボタンをクリックします。メモリの解放に関してはほとんど発生しないことに注意してください。

  4. ブラウザウィンドウを最小化し、再び最大化します。すべてのケースの90%で、ブラウザーは使用しない場合にメモリーをダンプし、実際にどれだけ消費するかを確認します。

ブラウザに500メガバイトのRAMを消費させることができます(上記の例ではありません)が、最小化して最大化すると、すべてが解放され、突然50メガバイトしか使用しなくなります。