2010-01-04 38 views
24

Từ những gì tôi nhớ lại quá khứ không xa, các phiên dịch Javascript bị các vấn đề rò rỉ bộ nhớ khi phải đối mặt với tham chiếu vòng tròn.javascript, tham chiếu vòng tròn và rò rỉ bộ nhớ

Nó vẫn là trường hợp trong các trình duyệt mới nhất? (Ví dụ như Chrome, FF 3.5 vv)

Trả lời

28

Phần lớn các rò rỉ chúng tôi nói về JavaScript là đặc biệt trong IE6-7 khi bạn tạo vòng lặp tham chiếu giữa các đối tượng JavaScript và các đối tượng lưu trữ như các nút DOM.

Trong IE6, điều này đặc biệt nguy hiểm khi bạn không lấy lại bộ nhớ khi rời khỏi trang; nó đã biến mất cho đến khi bạn thoát khỏi trình duyệt. Trong IE7 thanh toán bù trừ trang hiện nay trở lại bộ nhớ, nhưng bạn vẫn có thể gặp khó khăn khi bạn có một ứng dụng chạy dài. IE8 giải quyết hầu hết vấn đề này đúng cách bằng cách chuyển các nút DOM thành các đối tượng JavaScript gốc thay vì các đối tượng lưu trữ. (Bạn vẫn có thể kích hoạt rò rỉ trong IE8 bằng cách bao gồm các đối tượng không phải là bản địa khác như đối tượng ActiveX trong vòng lặp tham chiếu.)

Sẽ có những rò rỉ bộ nhớ nhỏ che khuất ngẫu nhiên ở tất cả các trình duyệt, đặc biệt là Các phiên bản cũ hơn. Nhưng không có cách nào để dễ dàng phân loại và tránh chúng như với vấn đề về bản đồ của IE.

+1

+1: dài tìm kiếm perl này của trí tuệ. –

+0

@Marco Demaio Hmm, http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html vẫn rò rỉ trong IE9 ở cả hai tiêu chuẩn hoặc chế độ quirks (win7 64bit), Hãy chắc chắn sử dụng quá trình thám hiểm khi giám sát byte riêng tư .. sigh .. –

+0

@AlexanderN: thực sự trên IE8 WXP trang bạn đề xuất không bị rò rỉ. Tôi sử dụng đơn giản "Windows Task Manager" ("Hiệu suất" tab) để xem nếu trang bị rò rỉ, trong trường hợp như vậy bạn sẽ thấy "PF sử dụng" ngày càng tăng. –

17

Để thêm vào bobince câu trả lời, tôi đã thực hiện một số thử nghiệm với IE8.

tôi đã cố gắng gần như tất cả các ví dụ được cung cấp tại http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

Không ai trong số họ được rò rỉ bộ nhớ nữa (ít nhất là không theo một cách nhận biết được), trừ các ví dụ mà loại bỏ nút con với các sự kiện vẫn còn gắn liền với chúng.

Loại ví dụ này tôi nghĩ giải thích rõ hơn là Douglas Crockford trong danh sách xếp hạng 2 của anh ấy.

Điều này vẫn rò rỉ bộ nhớ trên IE8 và nó khá dễ dàng để kiểm tra bằng cách chỉ cần chạy the test script và xem Windows Task Manager - Hiệu suất - PF Sử dụng. Bạn sẽ thấy PF Usage tăng thêm gần 1MB mỗi vòng lặp (rất nhanh).

Nhưng trong IE8 bộ nhớ được giải phóng trên trang dỡ bỏ (như điều hướng đến một trang mới hoặc tải lại cùng một trang) và rõ ràng cũng có khi hoàn toàn đóng trình duyệt. Vì vậy, để người dùng cuối cùng cảm nhận được rò rỉ bộ nhớ này trên IE8 (như giảm hiệu suất systerm), anh ta cần phải ở trên cùng một trang trong một thời gian dài, mà bây giờ nó có thể xảy ra thường xuyên với AJAX, nhưng trang này cũng cần phải thực hiện hàng trăm lần gỡ bỏ các phần tử con với sự kiện được đính kèm với chúng.

Kiểm tra Douglas Crockford đang nhấn mạnh trình duyệt với 10000 nút được thêm vào và sau đó xóa, điều đó thật tuyệt vời để hiển thị cho bạn vấn đề, nhưng trong thực tế tôi chưa bao giờ có trang xóa hơn 10 phần tử.INMHO thường nhanh hơn khi sử dụng display: none thay vì xóa toàn bộ các nút, đó là lý do tại sao tôi không sử dụng số removeChild nhiều.


Đối với bất cứ ai có thể quan tâm nhiều hơn trong bộ nhớ bị rò rỉ IE8 giải thích ở trên, tôi đã làm thử nghiệm khác và có vẻ như rò rỉ mem không hiển thị ở tất cả trong IE8 khi sử dụng innerHTML ở vị trí của appendChild/removeChild để thêm/xóa các phần tử con với các sự kiện đính kèm. Vì vậy, rõ ràng là Douglas Crockford purge function (gợi ý của anh ta để ngăn chặn rò rỉ bộ nhớ trong IE) là không cần thiết nữa trong IE8 ít nhất là khi sử dụng innerHTML ...

(EDITED nhờ 4esn0k bình luận dưới đây) ... hơn nữa Douglas Crockford purge function KHÔNG hoạt động ở tất cả trên IE8, trong mã của mình var a = d.attributes trả về thuộc tính NO onclick (hoặc bất kỳ thuộc tính khác onevent) được thêm vào khi chạy trên IE8 (chúng được trả về trên IE7).

Douglas Crockford nói:

"Chức năng thanh lọc nên được gọi là trước khi tháo bất kỳ yếu tố, một trong hai theo phương pháp removeChild, hoặc bằng cách thiết lập các innerHTML tài sản."

tôi cung cấp ở đây là mã cho thử nghiệm:

<body>  
    <p>queuetest2 similar to the one provided by Douglas Crockford 
    at http://www.crockford.com/javascript/memory/leak.html 
    <br>but this one adds/removes spans using innerHTML 
    instead of appendChild/removeChild.</p> 

    <div id="test"></div>  
    <script> 
     /* ORIGINAL queuetest2 CODE FROM DOUGLAS CROCKFORD IS HERE 
      http://www.crockford.com/javascript/memory/queuetest2.html */ 

     (function (limit, delay) 
     { 
      var n = 0; 
      var add = true; 

      function makeSpan(n) 
      { 
       var div = document.getElementById('test'); 
       //adding also an inline event to stress more the browser 
       div.innerHTML = "<span onmouseover=\"this.style.color = '#00ff00';\">" + n + "</span>"; 
       var s = div.getElementsByTagName('span')[0]; 
       s.onclick = function(e) 
       { 
        s.style.backgroundColor = 'red'; 
        alert(n); 
       }; 
       return s; 
      } 

      function process(n) 
      { 
       if(add)      
       s = makeSpan(n); 
       else 
       s.parentNode.innerHTML = ""; //removing span by clearing the div innerHTML 
       add = !add; 
      } 

      function loop() 
      { 
       if (n < limit) 
       { 
        process(n); 
        n += 1; 
        setTimeout(loop, delay); 
       } 
      } 

      loop(); 
     })(10000, 10); 

    </script> 
</body> 
+0

"Chức năng thanh lọc Douglas Crockford" có hữu ích cho IE 8 ở đây không? Có vẻ như, kể từ khi IE8 (ở chế độ IE8, chế độ không tương thích) "s.onclick" không được ánh xạ tới thuộc tính "onclick", do đó, không thể tìm thấy "onclick" trong các thuộc tính. Tôi có đúng không? – 4esn0k

+0

@ 4esn0k: xin lỗi nhưng tôi không chắc chắn về ý của bạn. –

+1

var s = document.createElement ('div'); s.onclick = function() {}; var a = s.attributes; cho (var i = 0; i 4esn0k

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