2010-03-11 73 views
40

我創建了一個網頁,每秒創建一次Ajax調用。在Internet Explorer 7中,它嚴重泄漏內存(大約15分鐘內20 MB)。簡單的jQuery Ajax調用在Internet Explorer中泄漏內存

該程序非常簡單。它只是運行一個可以進行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> 

如何堵塞此泄漏?我有一個真正的應用程序以這種方式更新大型表格,但無人照管會消耗千兆字節的內存。

編輯:沒關係,等以後一些很好的建議,我修改了代碼:

<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中泄漏。

有人建議在另一個虛擬機運行測試,看看結果是相同的。我找到了一臺運行Internet Explorer 8的XP Home的筆記本電腦,而不是設置另一臺虛擬機。它顯示了同樣的問題。

我嘗試了一些舊版本的jQuery,並獲得更好的結果,但直到我放棄了jQuery的Ajax和與更多的傳統(醜)阿賈克斯去的問題並沒有完全消失。

+0

兼談答案很好奇 - 我有想法,但想知道結果。 – Plynx 2010-03-11 22:14:32

+0

好問題,我不知道答案,但你可能會考慮在成功函數中使用setTimeout,所以如果你開始提出需要花費時間的請求,你不會重載服務器。如果您在發送下一個請求之前未收到來自服務器的全部響應,您將打開一個新的連接。 – MyGGaN 2010-03-11 22:20:36

+0

感謝關於移動setTimeout的建議。我試過了,但沒有幫助。 – 2010-03-11 22:29:11

回答

8

該問題似乎與Internet Explorer中的jQuery 1.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分鐘後大約100KB)。

我也試過一個版本我的計劃是,在一個更傳統的方式調用的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> 

這擺脫了泄漏的全部。

因此,看起來我必須做我的重複Ajax調用醜陋的舊方式,直到jQuery的人解決這個問題。

+1

是的,如果你想繼續做jQuery的方式,請在我的答案中使用補丁...實際上必須管理你的XHR的東西直接吸! – Ryley 2010-05-28 18:18:41

+0

有趣的是,在發佈時,我們仍然在當前的JQuery 1.6.2中出現問題。多次調用.getJSON會消耗越來越多的內存,直到您終止進程,即使您對內容無所作爲。 http://stackoverflow.com/questions/6752335/memory-leak-when-pulling-json-from-web – 2011-07-19 20:31:50

5

eval()會吃內存肯定(傳遞字符串時,setTimeout的評估EVAL發生),不使用它在測試:

setTimeout('testJunk()',1000); 

應該是:

setTimeout(testJunk, 1000); 

而且一個更好的使用總體將是setInterval()對於你想要的重複操作,試試這個:

setInterval(testJunk, 1000); 
+0

感謝您的建議。我嘗試過這個。如果它有所作爲,那就很小。記憶力仍在上升。 – 2010-03-11 22:30:42

+0

@Thomas - 是你的問題中的整個頁面,還是隻是一個縮寫版本,更多正在發生在完整版本? – 2010-03-11 22:34:31

+0

我正在運行上面列出的程序,除了我已經損壞了列表的URL。 – 2010-03-11 22:44:54

0

您的代碼有一個問題,如果您的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 - 最好閱讀關於該問題的評論:) – 2010-03-11 22:35:13

+0

謝謝。我做了改變,但我沒有注意到有什麼不同。 – 2010-03-12 14:42:21

7

我遇到了同樣的問題,整個上午都被困住了......直到幾分鐘前。問題是當您設置onreadystatechange處理程序時創建的循環引用,該IE不夠聰明可以中斷。因此,解決方案是明確地分解它。但是,顯然你不能從處理程序本身做到這一點(儘管如果你可以的話,它會很方便!)。

神奇聲明:

delete request['onreadystatechange']; 

你需要保持對於您設置了onreadystatechange每個XMLHttpRequest對象的記錄。然後,在readyState到達4之後的某個時刻,對對象做出魔法。如果您已經在執行重複的AJAX輪詢,則檢查清理請求的邏輯位置將處於相同的輪詢循環中。我定義了一個簡單的RequestTracker對象來管理我的請求。

這對我有效;我證實它解決了泄漏問題。這裏有一個特別的環節是一馬當先(我會發布更多,但StackOverflow上是不是讓我):

+1

+1偉大的研究,這一定很有用。 – Plynx 2010-04-02 16:01:28

19

這裏有一個link對jQuery的錯誤了,與此相伴作爲jQuery的1.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; 
          } 
        } 
      }; 

注意:這是正式固定的jQuery 1.4.4,所以最好的辦法是剛纔升級。

+2

這應該是被接受的答案。 +1 – 2010-11-06 02:22:16

+0

1.4.4沒有爲我解決它。 1.5雖然 – 2011-02-21 10:09:16

+0

我遇到了問題使用jQuery UI 1.8.5這個修復,得到JS錯誤「xhr.abort不是一個函數」。 – 2011-03-17 23:32:33

0

我見過這個,我不相信這是一個內存泄漏本身。只是因爲緩存,Ajax請求返回時沒有數據。

添加故意高速緩存控制,如:

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

這是哪裏的東西掉下裂縫的事情之一,就是做一個具體的東西與緩存和XMLHttpRequest的和jQuery不使用緩存關閉默認。

0

剛剛遇到這個我自己。我認爲這是最初與UI庫有關的事情,但是在我交換jQuery 1.5之後,它就消失了。我正在使用的1.4.2版本。 (1.4.4似乎沒有解決這個問題)。

0

如果您在javascript中使用setinterval並且沒有正確清除它,定時器可能會多次啓動,導致一堆調用。

嘗試像

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

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