web-dev-qa-db-ja.com

単純なjQueryAjax呼び出しがInternetExplorerのメモリリーク

毎秒Ajax呼び出しを行うWebページを作成しました。 Internet Explorer 7では、メモリリークがひどい(約15分で20 MB)。

プログラムはとてもシンプルです。 Ajax呼び出しを行うJavaScript関数を実行するだけです。サーバーは空の文字列を返し、JavaScriptコードはそれを処理しません。 setTimeoutを使用して毎秒関数を実行し、 Drip を使用して監視しています。

ソースは次のとおりです。

<html>
  <head>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('jquery', '1.4.2');
      google.load('jqueryui', '1.7.2');
    </script>
    <script type="text/javascript">
      setTimeout('testJunk()',1000);
      function testJunk() {
        $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
                 dataType: 'html',
                 success: function(data){}
               });
        setTimeout('testJunk()',1000)
      }
    </script>
  </head>
  <body>
    Why is memory usage going up?
  </body>
</html>

このリークを塞ぐ方法は?この方法で大きなテーブルを更新する実際のアプリケーションがありますが、放置するとギガバイトのメモリを消費します。

Edit:わかりました。いくつかの良い提案をした後、コードを次のように変更しました。

<html>
  <head>
    <script type="text/javascript" src="http://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load('jquery', '1.4.2');
      google.load('jqueryui', '1.7.2');
    </script>
    <script type="text/javascript">
      setTimeout(testJunk,1000);
      function testJunk() {
        $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
                 dataType: 'html',
                 success: function(data){setTimeout(testJunk,1000)}
               });
      }
    </script>
  </head>
  <body>
    Why is memory usage going up?
  </body>
</html>

しかし、それは何の違いももたらさなかったようです。私はDOMで何もしていません。また、Ajax呼び出しをコメントアウトすると、メモリリークが停止します。したがって、リークは完全にAjax呼び出しにあるように見えます。 jQuery Ajaxは本質的にある種の循環参照を作成しますか?もしそうなら、どうすればそれを解放できますか?ちなみに、Firefoxではリークしません。

誰かが別のVMでテストを実行し、結果が同じかどうかを確認することを提案しました。別のVMをセットアップするのではなく、実行中のラップトップを見つけましたXP Internet Explorer8のあるホーム。同じ問題が発生します。

古いバージョンのjQueryをいくつか試したところ、より良い結果が得られましたが、jQueryでAjaxを放棄し、より伝統的な(そして醜い)Ajaxを使用するまで、問題は完全には解消されませんでした。

40
Thomas Lane

この問題は、InternetExplorerのjQuery1.4にあるようですが、バージョン1.2および1.3にはそれほど問題はありません。

1.4.0、1.4.1、および1.4.2はすべて、深刻なメモリリークを示しました。

1.2.3、1.2.6、1.3.0、1.3.1、および1.3.2はすべて、はるかに小さなリークを示しました(10分後に約100 KB)。

また、より伝統的な方法でAjaxを呼び出すバージョンのプログラムも試しました。

<html>
  <head>
    <script language="javascript" type="text/javascript">
      function getHTTPObject() {
        var xmlhttp;
        /*@cc_on
        @if (@_jscript_version >= 5)
          try {
            xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
          } catch (e) {
            try {
              xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (E) {
              xmlhttp = false;
            }
          }
        @else
        xmlhttp = false;
        @end @*/
        if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
          try {
            xmlhttp = new XMLHttpRequest();
            if (xmlhttp.overrideMimeType) {
              xmlhttp.overrideMimeType("text/xml"); 
            }
          } catch (e) {
            xmlhttp = false;
          }
        }
        return xmlhttp;
      }
      var ajaxObject = getHTTPObject();
      setTimeout(testJunk,1000);
      function testJunk() {
        ajaxObject.open('POST', 'http://XXXXXXXXXXXXXXX/delme2', true);
        ajaxObject.onreadystatechange = handleAjaxResponse;
        ajaxObject.send(null);
      }
      function handleAjaxResponse() {
        if (ajaxObject.readyState==4) {
          setTimeout(testJunk,1000);
        }
      }
    </script>
  </head>
  <body>
    <div id="test">Why is memory usage going up?</div>
  </body>
</html>

これにより、漏れが完全になくなりました。

したがって、jQueryの人々がこの問題を解決するまで、Ajaxの呼び出しを醜い古い方法で繰り返す必要があるようです。

8
Thomas Lane

これは、jQueryのバグオーバーへの リンク と、jQuery1.4.2の推奨される修正としてのこれです。

--- jquery-1.4.2.js     2010-04-08 12:10:20.000000000 -0700
+++ jquery-1.4.2.js.fixed       2010-04-08 12:10:38.000000000 -0700
@@ -5219,7 +5219,7 @@

                            // Stop memory leaks
                            if ( s.async ) {
-                                       xhr = null;
+                                       xhr.onreadystatechange = null; xhr.abort = null; xhr = null;
                            }
                    }
            };

[〜#〜] note [〜#〜]:これはjQuery 1.4.4で正式に修正されているため、今すぐアップグレードすることをお勧めします。

19
Ryley

私は同じ問題に遭遇し、午前中ずっと困惑していました...少し前まで。問題は、onreadystatechangeハンドラーを設定したときに作成される循環参照であり、IEは、壊すほど賢くないため、解決策は、明示的に壊すことです。 。ただし、ハンドラー自体から実行することはできません(できれば便利ですが)。

魔法の声明:

delete request['onreadystatechange'];

XMLHttpRequestを設定した各onreadystatechangeオブジェクトの記録を保持する必要があります。次に、readyStateが4になった後のある時点で、オブジェクトに魔法をかけます。すでに繰り返しAJAXポーリングを実行している場合、クリーンアップ要求をチェックする論理的な場所は同じポーリングループ内になります。管理する単純なRequestTrackerオブジェクトを定義しました私の要求。

これは私にとってはうまくいきました。リークが解決したことを確認しました。特に道を開いた1つのリンクがあります(私はもっと投稿しますが、StackOverflowは私を許可していません):

7
Haw-Bin

eval()は確かにメモリを消費します(評価するために文字列をsetTimeoutに渡すときに評価が発生します)。テストでは使用しないでください。

_setTimeout('testJunk()',1000);
_

する必要があります:

_setTimeout(testJunk, 1000);
_

また、全体としてはsetInterval()を使用して、必要に応じて操作を繰り返すことをお勧めします。これを試してください。

_setInterval(testJunk, 1000);
_
5
Nick Craver

コードの問題の1つは、ajaxリクエストに時間がかかり始めた場合、ブラウザとサーバーにajaxリクエストが殺到し始めると、ブラウザがサーバーから戻るまで待ってから次のリクエストを開始する必要があることです。

function testJunk() {
    $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
        dataType: 'html',
        complete: function(data){
            setTimeout(testJunk,1000);
        }
    });
}
testJunk();
0
PetersenDidIt

javascriptでsetintervalを使用していて、それを適切にクリアしないと、タイマーが複数回開始され、呼び出しのスタックが発生する可能性があります。

次のようなものを試してください

var myVar = setInterval(function() { clear() }, 5000);

function clear() { 
    clearInterval(myVar); 
    GetData("ServiceLibrary","GetCalls",sdata,Complete);
};
0
sully

自分でこれに遭遇した。最初はUIライブラリと関係があると思っていましたが、jQuery 1.5に切り替えたところ、消えてしまいました。私が使用していたバージョン1.4.2の場合。 (1.4.4は問題を修正していないようです)。

0
James Wiseman

私はこれを見たことがありますが、それ自体がメモリリークではないと思います。キャッシュが原因で、Ajaxリクエストがデータなしで返されるだけです。

次のように、意図的なキャッシュ制御を追加します。

$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
         dataType: 'html',
         cache: false,
         success: function(data){}
    });
    setTimeout('testJunk()',1000)

これは、問題が発生する原因の1つです。つまり、キャッシュとXMLHttpRequestを使用して特定の処理を実行し、jQueryはデフォルトでキャッシュオフを使用しません。

0
nic ferrier