3

次の JavaScript コードはメモリ リークを起こしているようですが、その理由はわかりません。Chrome 19 と firefox 12 でこれを試しました。コードは以下のとおりです。

<body>
    <input id="add" type="button" value="add" onclick="add()" />
    <input id="remove" type="button" value="remove" onclick="remove()" />
    <div id="content">
    </div>
</body>

<script>
    var count = 0;

    function add() {
        var i = 0,
            newdiv;

        for (i = 0; i < 10000; i++) {
            newdiv = document.createElement('div');
            document.getElementById("content").appendChild(newdiv);
            newdiv.setAttribute('id', "div" + count);
            newdiv.innerHTML = "section " + count;
            newdiv = null;

            count = count + 1;
        }
    }

    function remove() {
        var i = 0;
        for (i = 0; i < count; i++) {
            document.getElementById("content").removeChild(document.getElementById("div" + i));
        }
        count = 0;
    }

</script>

追加ボタンをクリックしてから削除ボタンをクリックし続けると、 Windows タスク マネージャーのメモリが増加し続けます。ガベージ コレクションが開始されると、ある時点でメモリが減少することを期待していましたが、これは決して起こらないようです。

それで、私の質問は次のとおりです。このコードにメモリリークはありますか? もしそうなら、どうすればコードをリファクタリングしてリークを修正できますか?

4

2 に答える 2

2

私はこれをChrome19.0でテストしましたが、そうです、メモリが増加します。しかし、約30秒後、ガベージコレクションが開始され、通常の状態に戻ります。

于 2012-06-23T10:28:25.237 に答える
0

メモリリークがあることを実際に証明することはできません...しかし、良いスポーツゲームの後に10000本のボトルをクリーンアップしたいと想像してみてください。時間とリソースがかかります;)

いくつかの役立つコメントに加えて、クロージャーを使用して、ウィンドウオブジェクトからそのコードをカプセル化します。ドキュメントへのローカル参照を使用してスコープチェーンのウォークスルーを回避し、フラグメントを使用してすべての新しい div を追加し、毎回ドキュメントにアクセスしないようにし、関数のオーバーヘッドを回避します (これらはすべて単なる提案であり、必ずしも探しているものではありませんが、とにかく良いものです)そして、少なくとも問題を少し軽減する必要があります:)

注: これらの例のすべてがクロス ブラウザで完全に機能するとは限りません

<body>
  <input id="add" type="button" value="add">
  <input id="remove" type="button" value="remove">
  <div id="content"></div>
</body>
<script>
  (function(DOC) {
    var count = 0, getById = DOC.getElementById, createFragment = DOC.createDocumentFragment;

    getById("add").addEventListener("click", function() {
      var i = 0,
          newdiv,
          fragment = createFragment();

      for (; i < 10000; i++) {
        newdiv = document.createElement('div');
        newdiv.id = "div" + count;
        newdiv.innerHTML = "section " + count;

        fragment.appendChild(newdiv);
        delete newdiv;
      }
      getById("content").appendChild(fragment);
      count = i;
    }, false);

    getById("remove").addEventListener("click", function() {
      var element, i = 0;
      for (; i < count; i++) {
        element = getById("div" + i);
        element.parentNode.removeChild(element);
      }
      count = 0;
    }, false);

  })(document);
</script>

これが、リークの解決または少なくとも削減に役立つことを願っています。=)

于 2012-06-23T11:44:25.730 に答える