2010-03-11 34 views
40

Tôi đã tạo một trang web thực hiện cuộc gọi Ajax mỗi giây. Trong Internet Explorer 7, nó bị rò rỉ bộ nhớ kém (20 MB trong khoảng 15 phút).Cuộc gọi jQuery Ajax đơn giản rò rỉ bộ nhớ trong Internet Explorer

Chương trình rất đơn giản. Nó chỉ chạy một hàm JavaScript thực hiện cuộc gọi Ajax. Máy chủ trả về một chuỗi rỗng và mã JavaScript không làm gì với nó. Tôi sử dụng setTimeout để chạy các chức năng mỗi giây, và tôi đang sử dụng Drip để xem điều.

Dưới đây là nguồn:

<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> 

Làm thế nào để cắm rò rỉ này? Tôi có một ứng dụng thực sự cập nhật một bảng lớn theo cách này, nhưng không được giám sát, nó sẽ chiếm tới hàng gigabyte bộ nhớ.

Sửa: okay, vì vậy sau khi một số gợi ý tốt, tôi sửa đổi mã để:

<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> 

Nó dường như không thực hiện bất kỳ sự khác biệt, mặc dù. Tôi không làm bất cứ điều gì với DOM, và nếu tôi nhận xét về cuộc gọi Ajax, rò rỉ bộ nhớ sẽ dừng lại. Vì vậy, có vẻ như sự rò rỉ hoàn toàn trong cuộc gọi Ajax. Liệu jQuery Ajax vốn có tạo ra một dạng tham chiếu vòng tròn nào đó không, và nếu có, làm thế nào tôi có thể giải phóng nó? Nhân tiện, nó không bị rò rỉ trong Firefox.

Ai đó đã đề xuất chạy thử nghiệm trong một máy ảo khác và xem kết quả có giống nhau hay không. Thay vì thiết lập một máy ảo khác, tôi tìm thấy một máy tính xách tay đang chạy XP Home với Internet Explorer 8. Nó thể hiện cùng một vấn đề.

Tôi đã thử một số phiên bản cũ hơn của jQuery và có kết quả tốt hơn, nhưng vấn đề không biến mất hoàn toàn cho đến khi tôi bỏ Ajax trong jQuery và đi kèm với Ajax truyền thống (và xấu xí).

+0

Cũng rất tò mò về câu trả lời - Tôi có ý tưởng, nhưng muốn biết kết quả. – Plynx

+0

Câu hỏi hay, tôi không biết câu trả lời nhưng bạn có thể xem xét việc có setTimeout trong hàm thành công để bạn không bị quá tải máy chủ nếu bạn bắt đầu thực hiện các yêu cầu cần có thời gian. Trong trường hợp bạn không nhận được toàn bộ phản hồi từ máy chủ trước khi gửi yêu cầu tiếp theo, bạn sẽ mở một kết nối mới. – MyGGaN

+0

Cảm ơn bạn đã đề xuất về việc di chuyển setTimeout. Tôi đã thử nó, nhưng nó không giúp được gì. –

Trả lời

8

Sự cố có vẻ như với jQuery 1.4 trong Internet Explorer và ở mức độ thấp hơn, phiên bản 1.2 và 1.3.

1.4.0, 1.4.1 và 1.4.2 tất cả đều thể hiện sự rò rỉ bộ nhớ nghiêm trọng.

1.2.3, 1.2.6, 1.3.0, 1.3.1 và 1.3.2 tất cả hiển thị rò rỉ nhỏ hơn nhiều (khoảng 100 KB sau 10 phút).

Tôi cũng đã thử một phiên bản của chương trình của tôi mà các cuộc gọi Ajax một cách truyền thống hơn:

<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> 

này đã thoát khỏi những rò rỉ hoàn toàn.

Vì vậy, có vẻ như tôi sẽ phải lặp lại các cuộc gọi Ajax của tôi theo cách cũ xấu xí cho đến khi các folks jQuery giải quyết vấn đề này.

+1

Vâng, nếu bạn muốn tiếp tục làm mọi thứ theo cách jQuery, hãy sử dụng bản vá trong câu trả lời của tôi ... Thực ra phải quản lý công cụ XHR của bạn trực tiếp hút! – Ryley

+0

vui vẻ đủ, chúng tôi vẫn xuất hiện có vấn đề trong JQuery hiện tại, 1.6.2 tại thời điểm đăng bài. Nhiều cuộc gọi tới .getJSON tiêu thụ nhiều bộ nhớ hơn và nhiều hơn nữa cho đến khi bạn giết quá trình, ngay cả khi bạn không làm gì với nội dung. http://stackoverflow.com/questions/6752335/memory-leak-when-pulling-json-from-web –

5

eval() sẽ ăn lên bộ nhớ cho chắc chắn (eval xảy ra khi đi qua một chuỗi để setTimeout để đánh giá), không sử dụng nó trong thử nghiệm:

setTimeout('testJunk()',1000); 

nên là:

setTimeout(testJunk, 1000); 

Cũng tổng quan sử dụng tốt hơn sẽ là setInterval() cho một hoạt động lặp lại như bạn muốn, hãy thử điều này:

setInterval(testJunk, 1000); 
+0

Cảm ơn bạn đã đề xuất. Tôi đã thử nó. Nếu nó tạo ra sự khác biệt thì nó nhỏ. Bộ nhớ vẫn đang tăng lên. –

+0

@Thomas - Đó có phải là toàn bộ trang trong câu hỏi của bạn hay chỉ là một phiên bản viết tắt và nhiều thứ khác đang diễn ra trong phiên bản đầy đủ? –

+0

Tôi đang chạy chương trình như được liệt kê ở trên, ngoại trừ việc tôi đã làm hỏng url cho danh sách. –

0

Một vấn đề với mã của bạn là nếu yêu cầu ajax của bạn bắt đầu mất một lúc, bạn sẽ bắt đầu tràn ngập trình duyệt và máy chủ với yêu cầu ajax bạn thực sự phải chờ cho đến khi trình duyệt nhận được trả về từ máy chủ trước khi khởi động lại.

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

@petersendidit - Tốt nhất để đọc các nhận xét về câu hỏi :) –

+0

Cảm ơn. Tôi đã thay đổi, nhưng tôi không nhận thấy sự khác biệt. –

7

Tôi gặp phải vấn đề tương tự và đã được stumped tất cả các buổi sáng ... cho đến một vài phút trước đây. Vấn đề là một tham chiếu vòng tròn được tạo ra khi bạn đặt trình xử lý onreadystatechange, rằng IE không đủ thông minh để phá vỡ. Do đó, giải pháp là phá vỡ nó một cách rõ ràng. Tuy nhiên, rõ ràng bạn không thể làm điều đó từ bên trong trình xử lý (mặc dù nó sẽ thuận tiện nếu bạn có thể!).

Tuyên bố kỳ diệu:

delete request['onreadystatechange']; 

Bạn cần phải lưu giữ hồ sơ của từng đối tượng XMLHttpRequest mà bạn thiết lập onreadystatechange. Sau đó, tại một số điểm sau khi readyState chuyển sang 4, thực hiện phép thuật của bạn trên đối tượng. Nếu bạn đã thực hiện một cuộc thăm dò lặp lại AJAX, nơi hợp lý để kiểm tra các yêu cầu dọn dẹp sẽ nằm trong cùng một vòng lặp bỏ phiếu. Tôi đã xác định một đối tượng RequestTracker đơn giản để quản lý các yêu cầu của mình.

Điều này phù hợp với tôi; Tôi đã xác minh rằng nó đã giải quyết được sự rò rỉ. Dưới đây là một liên kết đặc biệt mà dẫn đường (Tôi sẽ gửi hơn, nhưng StackOverflow không cho tôi):

+1

+1 Nghiên cứu tuyệt vời, điều này chắc chắn sẽ hữu ích. – Plynx

19

Dưới đây là một link đến lỗi trên trên jQuery, cùng với điều này như một sửa chữa gợi ý cho 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; 
          } 
        } 
      }; 

LƯU Ý: Đây là chính thức cố định trong jQuery 1.4.4, vì vậy đặt cược tốt nhất của bạn là chỉ cần nâng cấp ngay.

+2

Đây phải là câu trả lời được chấp nhận. +1 –

+0

1.4.4 không khắc phục được cho tôi. 1.5 mặc dù –

+0

Tôi đã gặp sự cố khi sử dụng sửa lỗi này với jQuery UI 1.8.5, nhận lỗi JS "xhr.abort không phải là một hàm". –

0

Tôi đã thấy điều này và tôi không tin đó là sự rò rỉ bộ nhớ. Nó chỉ là yêu cầu Ajax trả về không có dữ liệu vì bộ nhớ đệm.

Thêm kiểm soát bộ nhớ cache cố ý, như trong:

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

Đó là một trong những điều mà những thứ rơi xuống vết nứt, có nghĩa là, không một điều cụ thể với bộ nhớ đệm và XMLHttpRequest và jQuery không sử dụng bộ nhớ cache tắt theo mặc định.

0

Chỉ gặp phải vấn đề này. Tôi nghĩ rằng đó là một cái gì đó để làm với thư viện giao diện người dùng ban đầu, nhưng sau đó nó biến mất sau khi tôi đổi chỗ trong jQuery 1.5. cho phiên bản 1.4.2 mà tôi đã sử dụng. (1.4.4 dường như không khắc phục được vấn đề).

0

nếu bạn đang sử dụng tập hợp trong javascript và không xóa nó đúng cách, bộ hẹn giờ có thể bắt đầu nhiều lần, gây ra một chồng các cuộc gọi.

thử một cái gì đó giống như

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

function clear() { 
    clearInterval(myVar); 
    GetData("ServiceLibrary","GetCalls",sdata,Complete); 
}; 
Các vấn đề liên quan