2011-11-13 17 views
8

Tôi đã nghiên cứu khá nhiều về điều này nhưng chủ yếu là bằng cách ghép các câu hỏi khác lại với nhau, mà vẫn còn một số nghi ngờ. Trong ứng dụng không làm mới trang trình duyệt bất kỳ lúc nào và có thể hoạt động trong một thời gian (mà không đóng) (giả sử làm mới trang hoặc điều hướng đến trang khác sẽ khởi động lại mã js), cách tốt nhất để đảm bảo đối tượng là gì phát hành và không có rò rỉ bộ nhớ.Cuộc sống của các đối tượng JavaScript & Rò rỉ bộ nhớ

Đây là những trường hợp cụ thể mà tôi quan tâm:

Tất cả mã bên dưới đều nằm trong mẫu mô-đun tiết lộ.

mycode = function(){}() 

biến phạm vi chức năng, tôi chắc chắn một điều này được thu thập bởi GC tốt

function(){ var h = "ss";} 

biến trong mô-đun, nên g = null khi nó không còn cần thiết?

var g; 
function(){ g = "dd";} 

Và cuối cùng là tuổi thọ của jqXHR: nó có được dọn dẹp sau khi trả về không? Nếu nó được đặt thành null trong mọi trường hợp như là một biện pháp phòng ngừa cho dù được giữ bên trong một chức năng hoặc mô-đun?

Nếu làm điều này, nó là x dọn dẹp bởi GC sau khi nó trả ?:

function(){ 
    var x = $.get(); 
    x.done = ...; 
    x.fail = ...; 
} 

Làm thế nào về việc khi làm điều này, nó cũng sẽ được dọn dẹp sau x lợi nhuận ?:

var x; 
function(){ 
    x = $.get(); 
    x.done = ...; 
    x.fail = ...; 
} 

Cuối cùng, có cách nào để dọn sạch tất cả các biến và khởi động lại một mô-đun mà không cần khởi động lại trình duyệt không?

+0

Nếu bạn đang suy nghĩ về rò rỉ bộ nhớ, bạn không nên suy nghĩ về các biến. Hãy suy nghĩ về các đối tượng và tài liệu tham khảo và các hàm ý khả năng tiếp cận mà sau này có cho các đối tượng. – delnan

+0

Vâng, nó chỉ là tôi nghĩ về tất cả mọi thứ trong js như một biến, nhưng tôi nhận được quan điểm của bạn. Cảm ơn. –

Trả lời

7

biến phạm vi chức năng, tôi chắc chắn một điều này được thu thập bởi GC tốt

Yes.

biến trong mô-đun, nên g = null khi không còn cần thiết?

chắc.

Và cuối cùng là tuổi thọ của jqXHR: nó có được dọn dẹp sau khi trả lại không? Nếu nó được đặt thành null trong mọi trường hợp như là một biện pháp phòng ngừa cho dù được giữ bên trong một chức năng hoặc mô-đun?

các trình duyệt khác nhau đã có lỗi liên quan đến XHR gây ra onreadystatechange và bất cứ điều gì nó đóng cửa hơn để duy trì uncollectable trừ khi dev đã cẩn thận để thay thế nó bằng một giá trị giả (xhr.onreadystatechange = new Function('')) nhưng tôi tin rằng jQuery xử lý việc này cho bạn.

Cuối cùng, có cách nào để dọn sạch tất cả biến và khởi động lại mô-đun mà không cần khởi động lại trình duyệt không?

Trạng thái toàn cầu được liên kết với trang sẽ chiếm bộ nhớ trình duyệt cho đến khi trang bị xóa khỏi ngăn lịch sử trình duyệt. location.replace có thể giúp bạn ở đây bằng cách cho phép bạn giết trang hiện tại và thay thế bằng phiên bản mới của cùng một ứng dụng mà không cần mở rộng ngăn xếp lịch sử.

Thay thế tài liệu hiện tại bằng tài liệu tại URL được cung cấp. Sự khác biệt từ phương pháp assign() là sau khi sử dụng replace() trang hiện tại sẽ không được lưu trong lịch sử phiên, nghĩa là người dùng sẽ không thể sử dụng nút Quay lại để điều hướng đến nó.

Khi bạn sử dụng từ "mô-đun", đó không phải là cụm từ có ý nghĩa rõ ràng với trình duyệt hoặc trình thông dịch JavaScript của nó để không có cách nào loại bỏ mô-đun và chỉ mô-đun khỏi bộ nhớ. Có một số điều mà bạn phải lo lắng về điều đó có thể giữ mọi thứ trong bộ nhớ:

  1. Tham chiếu đến các đối tượng JavaScript đã được đính kèm với nút DOM và mọi thứ mà chúng đóng trên - trình xử lý sự kiện là một ví dụ rất phổ biến.
  2. Sống setIntervalsetTimeout gọi lại và mọi thứ họ đóng lại.
  3. Thuộc tính của đối tượng toàn cầu và mọi thứ họ đóng.
  4. Như bạn đã lưu ý, các thuộc tính của một số đối tượng lưu trữ nhất định như các phiên bản XHR, các cuộc gọi lại của nhân viên web, v.v và (bạn đã đoán nó) mọi thứ mà chúng đóng lại.

Bất kỳ lược đồ nào sẽ hủy mô-đun và chỉ mô-đun cần xử lý tất cả các mô đun này và tìm ra mô đun nào trong số đó là một phần của mô-đun. Đó là rất nhiều loại khác nhau của dọn dẹp.

+0

'delete' chỉ hoạt động cho các thuộc tính, không phải cho' g' ở đây. http://jsfiddle.net/hM5ke/ – pimvdb

+0

@pimvdb, cảm ơn. Đã chỉnh sửa. –

+0

IYO, bạn sẽ ** đề xuất ** rằng biến jqXHR được đặt thành null khi không còn cần thiết nữa? Tôi chỉ cần thiết lập một jqXHR; nhận được phản hồi của tôi, tải html mới trong div mà nó đã ở và tôi vẫn có thể truy cập biến. Trong khi tôi đánh giá cao GC sẽ làm điều đó (cuối cùng), nó sẽ là tốt nhất để null nó? hoặc để js gc làm điều đó? –

1

Javascript là ngôn ngữ được thu thập rác. Nó dựa vào bộ thu gom rác để dọn dẹp bộ nhớ không sử dụng. Vì vậy, về cơ bản, bạn phải tin tưởng rằng GC sẽ thực hiện công việc của mình.

GC sẽ (cuối cùng, không nhất thiết phải ngay lập tức) thu thập các đối tượng không thể truy cập được với bạn. Nếu bạn có một tham chiếu đến một đối tượng, thì nó có khả năng vẫn được sử dụng, và do đó GC sẽ không chạm vào nó.

Nếu bạn không có tham chiếu đến đối tượng, trực tiếp hoặc gián tiếp, thì GC biết rằng đối tượng không thể được sử dụng và đối tượng có thể được thu thập. Vì vậy, tất cả các bạn phải làm, thực sự, là chắc chắn rằng bạn đặt lại bất kỳ tài liệu tham khảo cho đối tượng.

Tuy nhiên, GC không đảm bảo về số khi đối tượng sẽ được thu thập. Và bạn không cần phải lo lắng về điều đó.

1

Thực sự những rò rỉ duy nhất bạn nên lo lắng về việc đóng cửa.

function foo(a){ 
    var b = 10 + a; 
    return function(c){ 
     return b + c; 
    } 
} 

var bar = foo(20); 
var baz = bar(5); 

GC không có cách nào để xóa var b - không nằm trong phạm vi. Đây là một vấn đề lớn với IE, không nhiều với Mozilla và ít hơn nhiều với Chrome.

+0

Tất nhiên, đó không phải là rò rỉ vĩnh viễn. Khi hàm trả về của GC get thì 'b' cũng sẽ nhận được GC'd. – Raynos

+0

Nếu tôi không nhầm, 'b' được GC'd khi không có tham chiếu đến hàm trả về vì đó là nơi duy nhất có tham chiếu đến b sau khi' foo' trả về. –

+0

http://msdn.microsoft.com/en-us/library/bb250448(v=vs.85).aspx – AlienWebguy

0

Ví dụ đầu tiên với 'g', g phải được đặt thành rỗng. Nó sẽ giữ con trỏ đến "dd" nếu không.

Trong ví dụ thứ hai, 'x' trong trường hợp đầu tiên không cần phải được đặt thành rỗng, vì biến đó sẽ "biến mất" khi hàm xung quanh thoát. Trong trường hợp thứ hai, với 'x' bên ngoài hàm, 'x' sẽ giữ lại bất kỳ thứ gì được gán cho nó, và nó sẽ không được GC cho đến khi 'x' được đặt thành null hoặc cái gì khác.

+1

'" dd "' là một chuỗi nguyên thủy và chỉ là giá trị đó; không phải là "con trỏ" đối với một cái gì đó trong JavaScript. – pimvdb

+0

@pimvdb, tùy thuộc vào cách trình thông dịch thu thập các chuỗi ký tự chuỗi xảy ra trong các thân hàm, trình duyệt có thể loại bỏ bộ nhớ được sử dụng để lưu trữ "" dd "' sau hàm 'function() {g =" dd " ; } 'được thu thập. –

1

Mọi biến mà bạn không thể truy cập có thể được GC thu thập nữa. Nếu bạn khai báo một biến bên trong một hàm, khi hàm bị hủy, biến số có thể sẽ bị xóa. Nó , khi máy tính hết bộ nhớ hoặc vào bất kỳ lúc nào khác.

Điều này trở nên phức tạp hơn khi bạn thực thi các hàm không đồng bộ như XHR. Các số được thực hiệnkhông thành công có thể truy cập tất cả các biến được khai báo trong các hàm bên ngoài. Vì vậy, miễn là thực hiệnlỗi có thể được thực hiện, tất cả các biến phải nằm trong bộ nhớ. Khi yêu cầu kết thúc, các biến có thể được giải phóng.

Dù sao, bạn chỉ cần đảm bảo rằng mọi biến được khai báo càng sâu càng tốt.

+0

Không có sự đảm bảo nào như một biến * bị xóa khi chức năng này được bỏ. Nó chỉ * có thể * được gỡ bỏ từ thời điểm đó. – pimvdb

+0

Ok, tôi đã sửa lỗi này. Người hỏi hỏi về rò rỉ bộ nhớ và những người xuất hiện nếu các biến không thể được thu thập. – Yogu

+0

@pimvdb, tôi đồng ý với 'is' so với' can', nhưng khung kích hoạt là các đối tượng và không phải chúng cũng như các thuộc tính đóng mà chúng chứa đều có thể thu nếu có một phần phạm vi của bất kỳ đóng cửa trực tiếp nào. Các thay đổi đối với ngữ nghĩa 'eval' trong ES5 cho phép đóng để tham chiếu đến một tập hợp con của một khung kích hoạt - một số thuộc tính chứ không phải các thuộc tính khác - nhưng giá trị biến cục bộ không phải lúc nào cũng thu được chỉ vì khung kích hoạt mà chúng xuất hiện đã bị thoát. –

1

Theo quy tắc chung với bất kỳ ngôn ngữ thu gom rác nào (ví dụ: Java, .NET và JavaScript), bạn cần đảm bảo rằng không có tham chiếu kéo dài tới khối bộ nhớ mà bạn muốn có GC làm sạch cho bạn. Khi GC nhìn vào một khối bộ nhớ và thấy rằng vẫn còn một cái gì đó trong chương trình tham chiếu nó, sau đó nó sẽ tránh phát hành nó.

Đối với jqXHR, không có điểm nào trong việc bạn đặt chúng thành null khi kết thúc cuộc gọi hàm AJAX. Tất cả các tham số của một thành công/lỗi/hoàn thành AJAX sẽ được giải phóng khi hàm trả về bởi GC trừ khi jQuery đang thực hiện một điều kỳ lạ như giữ một tham chiếu đến chúng.

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