2011-04-18 78 views
14

Tôi cần cập nhật nhiều dữ liệu trong một khoảng thời gian nhất định bằng JavaScript. Vấn đề là, không có vấn đề gì về thư viện JS tôi sử dụng (ngay cả js xương trần), rằng tất cả các trình duyệt dường như phân bổ bộ nhớ trên mọi yêu cầu AJAX và không thể giải phóng nó sau đó. Đây là một mẫu snipped rằng nên sao chép các lỗi:Trình duyệt tiếp tục ăn bộ nhớ với AJAX + setInterval

<!DOCTYPE html> 
    <html lang="en"> 
     <head> 
      <title>Memleak Test</title> 
      <meta charset="utf-8" /> 
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script> 
      <script type="text/javascript"> 

       function readData() { 
        $.getJSON('data.php'); 
       } 

       $(document).ready(function() { 
        setInterval(readData, 1000); 
       }); 
      </script> 
     </head> 
     <body> 
      <div id="content"></div> 
     </body> 
    </html> 

Một trang kiểm tra tương đương có sẵn tại jsbin

Dưới đây là thông tin thêm về điều này:

  • Tôi cũng đã cố gắng để đưa readData() chức năng như một đóng cửa trực tiếp trong cuộc gọi setInterval(). Điều này dường như không tạo ra bất kỳ sự khác biệt nào.
  • Tôi sử dụng jQuery ở đây, nhưng bất kỳ Thư viện nào khác cũng sẽ tạo ra cùng một lỗi.
  • Tập lệnh data.php của tôi chỉ tạo JSON-Object giả với json_encode() bằng PHP.
  • Tôi biết rằng một giây là khung thời gian ngắn ở đây, trong kịch bản sản xuất của tôi, khung thời gian là 30 giây. Tôi chỉ muốn nhìn thấy hiệu ứng nhanh hơn (trong ứng dụng sản xuất phải mất nhiều giờ nhưng sau đó bộ nhớ là đầy đủ quá).
  • Vấn đề ở đây là ứng dụng sẽ mở 24/7.

Có vẻ đơn giản đến mức tôi nghĩ mình đang làm điều gì đó sai ở đây, sẽ rất tuyệt nếu một số chuyên gia JS ở đây có thể giúp tôi!

+1

Trong * kiểm tra * thực sự của bạn được bạn thao tác DOM, qua '.html' hay? – karim79

+0

karim79, trong môi trường sản xuất của tôi tất nhiên tôi thao tác DOM. Khi tôi cố gắng để theo dõi vấn đề, tôi có thể thu hẹp nó xuống để gọi ajax và ngạc nhiên của tôi này "rò rỉ" cũng xảy ra mà không cần bất kỳ thao tác DOM. Tôi cho rằng trình duyệt không thể giải phóng bộ nhớ được cấp phát bên trong cuộc gọi setIntervall, nhưng tôi không biết cách làm việc đó. – daschl

+0

Điều gì sẽ xảy ra nếu bạn thay đổi nó để mỗi yêu cầu N, nó làm mới trang trình duyệt thay vì thực hiện cuộc gọi AJAX? – notJim

Trả lời

0

bạn đang bỏ phiếu sau mỗi giây. Chắc chắn nó sẽ tiêu thụ tất cả bộ nhớ. Tuy nhiên, bạn có thể làm gì để đặt khoảng thời gian được xác định trước. Sau đó, sau khi bỏ phiếu nếu dữ liệu có sẵn lấy và giữ khoảng thời gian giống nhau, nhưng nếu sau khi bỏ phiếu thì không có sẵn dữ liệu, tăng khoảng thời gian để đảm bảo cuộc thăm dò tiếp theo bị trì hoãn. Bằng cách này bạn có thể giảm tải.

+0

Xin chào Ahmad, cảm ơn phản hồi của bạn. Tôi đã nói trong bài viết đầu tiên của tôi rằng điều này được thiết lập để 30 giây trong sản xuất và chỉ cần thiết lập để một giây để các vấn đề của conp hiển thị nhanh hơn. Ngoài ra, tôi không thể thêm sự chậm trễ vì sau 2 giờ khả năng dữ liệu mới cũng giống như bây giờ. Dù sao cũng cảm ơn bạn! – daschl

+0

@moidaschl Được rồi, ngoài việc làm sạch bộ nhớ (Bộ sưu tập rác), bạn phải đặt các chỉ số trên mỗi lần tải dữ liệu và không được tải tất cả mọi thứ nhưng chỉ từ chỉ báo đó. Tôi hy vọng bạn hiểu ý tôi. –

+0

Hm không thực sự, nó sẽ là tuyệt vời nếu bạn có thể giải thích rằng công cụ chỉ số nhiều hơn một chút (hoặc bạn có một số liên kết có sẵn về chủ đề đó?) – daschl

0

Hãy xem bài đăng này - có thể hữu ích?

How can I force Javascript garbage collection in IE? IE is acting very slow after AJAX calls & DOM manipulation

(Gợi ý sử dụng phương pháp JQuery cụ thể mà dường như cố gắng tránh rò rỉ bộ nhớ: và sử dụng một 'xóa' lệnh để thử và giải phóng dung lượng).

+0

Cảm ơn bạn đã liên kết. Trên thực tế nó xảy ra trong tất cả các trình duyệt, không chỉ là IE. Lúc đầu tôi nghĩ rằng thao tác dữ liệu của tôi đang tạo ra sự tăng bộ nhớ này, nhưng sau đó tôi chỉ chạy truy vấn AJAX (như bạn có thể thấy trong ví dụ trên) và không làm gì khác và nó vẫn tăng lên. Tôi cũng đã thử html() và xóa các công cụ nhưng nó không giúp đỡ trong trường hợp này. Dù sao cũng cảm ơn bạn! – daschl

+0

Lưu ý, việc sử dụng xóa là một ý tưởng tồi, nếu bạn đang đọc câu trả lời này vào hoặc sau năm 2013, đừng sử dụng câu trả lời –

0

Bạn sẽ tăng mức sử dụng bộ nhớ vì bạn đang tải thêm dữ liệu theo mọi yêu cầu.

Clicky:

How to free memory after an Ajax request

Memory leak involving jQuery Ajax requests

+0

Xin chào Calum, cảm ơn các liên kết. Người đầu tiên chỉ nói rằng tôi không thể làm gì về nó, mà không phải là một lựa chọn ở đây: D. Điều thứ hai liên quan đến việc thao tác DOM mà tôi không làm ở đây và bộ nhớ vẫn tăng. Trong ứng dụng sản xuất của tôi, tôi điều khiển chúng DOM, và có lẽ $ .fn.removefromdom này giúp giảm bớt một chút.cảm ơn :) – daschl

0

Theo this jQuery forum thread:

... 
success: function(data) { 

    // the line below prevents the leak, apparently 
    document.getElementById("theContainer").innerHTML = ""; 
    $("#theContainer").html(data); 
} 
+0

hm tôi đã thử điều này, và cũng thay đổi thời gian đến 10 giây nhưng bạn có thể thấy rõ ràng trong công việc quản lý mà trên mọi yêu cầu mem đi lên nhưng trong khoảng thời gian bộ nhớ không bị loại bỏ. – daschl

+0

Tôi không thay đổi bất cứ điều gì. –

0

Bạn đã cố gắng tái sử dụng các biến bên trong các cuộc gọi của bạn? Có nghĩa là thay vì tạo các biến mới mà bạn xử lý phản hồi, chỉ cần sử dụng các biến tương tự. Nói

window.myvar = response["myvar"]; 

Nó thực sự là một rò rỉ, điều này có thể giúp người thu gom rác. Nó sẽ được tốt đẹp để xem mã thực tế của những gì bạn đang làm mặc dù.

4

Một vấn đề có thể xảy ra với cùng một bài đăng là nếu yêu cầu XHR mất nhiều thời gian hơn khoảng thời gian thăm dò (trung bình) sẽ có hàng đợi ngày càng tăng của yêu cầu đang chờ xử lý. Nếu bản thân máy chủ web bắt đầu yêu cầu backlog, điều này có thể biến thành một vòng luẩn quẩn.

Để tránh trường hợp có thể xảy ra này, hãy sử dụng mã hóa kiểu CPS trong đó hành động tiếp theo được thực hiện bằng cách sử dụng các cuộc gọi lại thích hợp. Tức là, không bắt đầu yêu cầu tiếp theo cho đến khi được yêu cầu (yêu cầu trước hoàn tất: thành công hay thất bại) - phương pháp này vẫn có thể được sử dụng để tạo hàng đợi yêu cầu thủ công với kích thước có thể điều khiển được nếu cần nhiều yêu cầu chưa xử lý.

Ngoài ra, hãy đảm bảo rằng các đối tượng không sử dụng đủ điều kiện để cải tạo vì đây là nguyên nhân "tiêu chuẩn" của "rò rỉ bộ nhớ" bằng ngôn ngữ GC.

Mã hóa vui vẻ.


Các mã trong bài viết chứa đựng gì mà vốn sẽ bị rò rỉ bộ nhớ. Nó có thể có thể là một vấn đề nội bộ với jQuery, nhưng đây chỉ là suy đoán. Ngoài ra, các công cụ như Firebug giám sát các yêu cầu XHR/web có thể tiêu thụ lượng bộ nhớ đáng kể vì vậy nó là một cái gì đó để kiểm tra và đảm bảo rằng hành vi không phải là Heisenberg.


Ngoài ra, hãy nhớ rằng việc tăng mức sử dụng bộ nhớ không thể hiện rò rỉ bộ nhớ trừ khi phát triển không bị chặn. Chu trình thu gom rác sẽ chỉ xảy ra khi các máy chủ cảm thấy thích.

+0

Xin chào, cảm ơn vì phản hồi và suy nghĩ của bạn về điều này. Tôi đã cố gắng sử dụng setTimeouts "thành công" thay vì setIntervals, nhưng tiếc là điều này không thay đổi vấn đề. Bây giờ tôi nghĩ rằng nó không thực sự là một rò rỉ bộ nhớ, nhưng nó có thể là khi bạn tải một bó của HTML có thể nó được đính kèm hoặc một cách nào đó ràng buộc với DOM và không bao giờ phát hành. Vì vậy, (như đã nói trong bình luận khác của tôi ở trên), có lẽ đó là một ý tưởng tốt để tải một số JSON thay vào đó và render nó. Tôi cũng nghĩ rằng vấn đề sẽ không xuất hiện trong sản xuất NẾU người dùng sẽ không mở ứng dụng 24/7. Khoảng thời gian sản xuất là 30 giây .... – daschl

+0

... cần đủ thời gian để giải phóng các phần tử dom cũ. Đáng buồn thay, nó cũng xảy ra với IE (nơi chúng ta không có firebug). Tôi tự hỏi làm thế nào các "người chơi lớn" như facebook hoặc twitter xử lý trường hợp này trong môi trường của họ (trò chuyện, luồng thời gian thực và v.v.). – daschl

3

Chỉ là một ý nghĩ, thay vì setInterval bạn nên sử dụng setTimeout và sau đó khi nó lần ra bạn đặt thời gian chờ một lần nữa.

Bằng cách đó bạn không chạy các nguy cơ của setInterval chạy ra nếu bạn bị mất theo dõi của nó đối với một số lý do:

Tôi cũng là ajax jquery có nghĩ callback thành công mà bạn có thể sử dụng như là điểm mà bạn setTimeout. Bằng cách đó, như đã được đề cập trong chủ đề này ở nơi khác, bạn không kết thúc các yêu cầu trùng lặp.

(chỉ cần kiểm tra và có một callback thành công)

+0

hi rtpHarry, cảm ơn phản hồi của bạn. Như đã nói trong bình luận của tôi ở trên tôi đã cố gắng này và nó không thay đổi tải bộ nhớ - thật đáng buồn. Dù sao cũng cảm ơn bạn! – daschl

Các vấn đề liên quan