Bộ sưu tập rác JavaScript là gì? Điều gì quan trọng đối với một lập trình viên web để hiểu về bộ sưu tập rác JavaScript, để viết mã tốt hơn?
Bộ sưu tập rác JavaScript là gì? Điều gì quan trọng đối với một lập trình viên web để hiểu về bộ sưu tập rác JavaScript, để viết mã tốt hơn?
Câu trả lời:
Eric Lippert đã viết một bài đăng trên blog chi tiết về chủ đề này một thời gian trước (ngoài ra so sánh nó với VBScript ). Chính xác hơn, ông đã viết về JScript , đây là triển khai ECMAScript của riêng Microsoft, mặc dù rất giống với JavaScript. Tôi sẽ tưởng tượng rằng bạn có thể cho rằng phần lớn hành vi sẽ giống với công cụ JavaScript của Internet Explorer. Tất nhiên, việc triển khai sẽ thay đổi tùy theo trình duyệt, mặc dù tôi nghi ngờ bạn có thể áp dụng một số nguyên tắc chung và áp dụng chúng cho các trình duyệt khác.
Trích dẫn từ trang đó:
JScript sử dụng trình thu gom rác đánh dấu và quét không cần thiết. Nó hoạt động như thế này:
Mỗi biến "trong phạm vi" được gọi là "scavenger". Một người nhặt rác có thể đề cập đến một số, một đối tượng, một chuỗi, bất cứ điều gì. Chúng tôi duy trì một danh sách những người nhặt rác - các biến được chuyển sang danh sách scav khi chúng đi vào phạm vi và ngoài danh sách scav khi chúng đi ra khỏi phạm vi.
Thỉnh thoảng người thu gom rác chạy. Đầu tiên, nó đặt một "dấu" trên mọi đối tượng, biến, chuỗi, v.v. - tất cả bộ nhớ được theo dõi bởi GC. (JScript sử dụng cấu trúc dữ liệu VariANT bên trong và có rất nhiều bit không được sử dụng thêm trong cấu trúc đó, vì vậy chúng tôi chỉ đặt một trong số chúng.)
Thứ hai, nó xóa dấu hiệu trên các scavengers và đóng cửa tạm thời của các tài liệu tham khảo scavenger. Vì vậy, nếu một đối tượng scavenger tham chiếu đến một đối tượng nonscavenger thì chúng ta sẽ xóa các bit trên nonscavenger và trên tất cả mọi thứ mà nó đề cập đến. (Tôi đang sử dụng từ "đóng cửa" theo nghĩa khác với trong bài viết trước đây của tôi.)
Tại thời điểm này, chúng ta biết rằng tất cả bộ nhớ vẫn được đánh dấu là bộ nhớ được phân bổ không thể đạt được bởi bất kỳ đường dẫn nào từ bất kỳ biến trong phạm vi nào. Tất cả những đối tượng đó được hướng dẫn tự xé xuống, phá hủy mọi tham chiếu vòng tròn.
Mục đích chính của thu gom rác là cho phép lập trình viên không phải lo lắng về việc quản lý bộ nhớ của các đối tượng họ tạo và sử dụng, mặc dù đôi khi không tránh khỏi điều đó - đôi khi luôn có một ý tưởng sơ bộ về cách thức hoạt động của bộ sưu tập rác .
Ghi chú lịch sử: bản sửa đổi trước đó của câu trả lời có tham chiếu không chính xác đến delete
toán tử. Trong JavaScript , delete
toán tử loại bỏ một thuộc tính khỏi một đối tượng và hoàn toàn khác với delete
C / C ++.
delete
không chính xác; ví dụ, trong ví dụ đầu tiên, thay vì delete foo
, trước tiên bạn nên loại bỏ trình nghe sự kiện thông qua window.removeEventListener()
và sau đó sử dụng foo = null
để ghi đè lên biến; trong IE, delete window.foo
(nhưng không delete foo
) cũng sẽ hoạt động nếu foo
là toàn cầu, nhưng ngay cả khi đó nó sẽ không ở FF hoặc Opera
delete
là một toán tử đơn nguyên (một biểu thức), không phải là một câu lệnh (tức là delete 0, delete 0, delete 3
:). Nó trông giống như tuyên bố khi được thể hiện bằng một tuyên bố biểu thức.
Cảnh giác với các tham chiếu vòng tròn khi các đối tượng DOM có liên quan:
Các mẫu rò rỉ bộ nhớ trong JavaScript
Hãy nhớ rằng bộ nhớ chỉ có thể được thu hồi khi không có tham chiếu hoạt động đến đối tượng. Đây là một cạm bẫy phổ biến với các bao đóng và xử lý sự kiện, vì một số công cụ JS sẽ không kiểm tra biến nào thực sự được tham chiếu trong các hàm bên trong và chỉ giữ tất cả các biến cục bộ của các hàm kèm theo.
Đây là một ví dụ đơn giản:
function init() {
var bigString = new Array(1000).join('xxx');
var foo = document.getElementById('foo');
foo.onclick = function() {
// this might create a closure over `bigString`,
// even if `bigString` isn't referenced anywhere!
};
}
Một triển khai JS ngây thơ không thể thu thập bigString
miễn là xung quanh xử lý sự kiện. Có một số cách để giải quyết vấn đề này, ví dụ: cài đặt bigString = null
ở cuối init()
( delete
sẽ không hoạt động đối với các biến cục bộ và đối số hàm: delete
xóa các thuộc tính khỏi các đối tượng và đối tượng biến không thể truy cập - ES5 ở chế độ nghiêm ngặt thậm chí sẽ ném ReferenceError
nếu bạn thử để xóa một biến cục bộ!).
Tôi khuyên bạn nên tránh đóng cửa không cần thiết càng nhiều càng tốt nếu bạn quan tâm đến việc tiêu thụ bộ nhớ.
Trích dẫn tốt từ một blog
Thành phần DOM là "rác được thu thập", cũng như thành phần JScript, có nghĩa là nếu bạn tạo một đối tượng trong một trong hai thành phần, và sau đó mất dấu vết của đối tượng đó, cuối cùng nó sẽ bị xóa.
Ví dụ:
function makeABigObject() {
var bigArray = new Array(20000);
}
Khi bạn gọi hàm đó, thành phần JScript sẽ tạo một đối tượng (được đặt tên là bigArray) có thể truy cập được trong hàm. Tuy nhiên, ngay sau khi hàm trả về, bạn "mất dấu" của bigArray vì không còn cách nào để tham khảo nó nữa. Chà, thành phần JScript nhận ra rằng bạn đã mất dấu vết của nó và vì vậy bigArray đã được dọn sạch - bộ nhớ của nó được lấy lại. Loại tương tự hoạt động trong thành phần DOM. Nếu bạn nói document.createElement('div')
, hoặc một cái gì đó tương tự, thì thành phần DOM tạo một đối tượng cho bạn. Khi bạn mất dấu vết của đối tượng đó bằng cách nào đó, thành phần DOM sẽ dọn sạch các liên quan.
Theo hiểu biết tốt nhất của tôi, các đối tượng của JavaScript là rác được thu thập định kỳ khi không còn tài liệu tham khảo nào cho đối tượng. Đó là điều xảy ra tự động, nhưng nếu bạn muốn xem thêm về cách thức hoạt động của nó, ở cấp độ C ++, hãy xem mã nguồn WebKit hoặc V8
Thông thường, bạn không cần phải suy nghĩ về nó, tuy nhiên, trong các trình duyệt cũ hơn, như IE 5.5 và các phiên bản đầu tiên của IE 6, và có lẽ các phiên bản hiện tại, việc đóng cửa sẽ tạo ra các tham chiếu vòng tròn mà khi không được kiểm tra sẽ làm hết bộ nhớ. Trong trường hợp cụ thể mà tôi muốn nói về việc đóng cửa, đó là khi bạn thêm một tham chiếu JavaScript vào một đối tượng dom và một đối tượng cho một đối tượng DOM được gọi lại cho đối tượng JavaScript. Về cơ bản, nó không bao giờ có thể được thu thập và cuối cùng sẽ khiến HĐH trở nên không ổn định trong các ứng dụng thử nghiệm được lặp để tạo sự cố. Trong thực tế, các rò rỉ này thường nhỏ, nhưng để giữ cho mã của bạn sạch sẽ, bạn nên xóa tham chiếu JavaScript đến đối tượng DOM.
Thông thường nên sử dụng từ khóa xóa để ngay lập tức hủy tham chiếu các đối tượng lớn như dữ liệu JSON mà bạn đã nhận lại và thực hiện bất cứ điều gì bạn cần làm với nó, đặc biệt là trong phát triển web di động. Điều này gây ra lần quét tiếp theo của GC để loại bỏ đối tượng đó và giải phóng bộ nhớ của nó.
mark-and-sweep
thuật toán phong cách mới hơn đảm nhận việc này .
thu gom rác (GC) là một hình thức quản lý bộ nhớ tự động bằng cách loại bỏ các đối tượng không cần thiết nữa.
mọi quá trình xử lý bộ nhớ đều tuân theo các bước sau:
1 - phân bổ dung lượng bộ nhớ bạn cần
2 - làm một số xử lý
3 - giải phóng không gian bộ nhớ này
Có hai thuật toán chính được sử dụng để phát hiện đối tượng nào không cần thiết nữa.
Bộ sưu tập rác đếm tham chiếu : thuật toán này giảm định nghĩa "một đối tượng không còn cần thiết nữa" thành "một đối tượng không có đối tượng nào khác tham chiếu đến nó", đối tượng sẽ xóa nếu không có điểm tham chiếu đến nó
Thuật toán đánh dấu và quét : kết nối từng đối tượng với nguồn gốc. bất kỳ đối tượng nào không kết nối với root hoặc đối tượng khác. đối tượng này sẽ bị xóa.
hiện nay hầu hết các trình duyệt hiện đại sử dụng thuật toán thứ hai.
"Trong khoa học máy tính, bộ sưu tập rác (GC) là một hình thức quản lý bộ nhớ tự động. Trình thu gom rác, hoặc chỉ là trình thu gom, cố gắng lấy lại rác hoặc bộ nhớ được sử dụng bởi các đối tượng sẽ không bao giờ được truy cập hoặc biến đổi bởi ứng dụng."
Tất cả các công cụ JavaScript đều có trình thu gom rác riêng và chúng có thể khác nhau. Hầu hết thời gian bạn không phải đối phó với họ vì họ chỉ làm những gì họ phải làm.
Viết mã tốt hơn chủ yếu phụ thuộc vào mức độ bạn biết các nguyên tắc lập trình, ngôn ngữ và cách triển khai cụ thể.
Bộ sưu tập rác JavaScript là gì?
kiểm tra cái này
Điều gì quan trọng đối với một lập trình viên web để hiểu về bộ sưu tập rác JavaScript, để viết mã tốt hơn?
Trong Javascript, bạn không quan tâm đến việc cấp phát và phân bổ bộ nhớ. Toàn bộ vấn đề được yêu cầu cho trình thông dịch Javascript. Rò rỉ vẫn có thể có trong Javascript, nhưng chúng là lỗi của trình thông dịch. Nếu bạn quan tâm đến chủ đề này, bạn có thể đọc thêm trong www.memoryman Quản lý.org
Trên cửa sổ, bạn có thể sử dụng Drip.exe để tìm rò rỉ bộ nhớ hoặc kiểm tra xem thói quen mem miễn phí của bạn có hoạt động không.
Điều đó thực sự đơn giản, chỉ cần nhập URL trang web và bạn sẽ thấy mức tiêu thụ bộ nhớ của trình kết xuất IE tích hợp. Sau đó nhấn refresh, nếu bộ nhớ tăng, bạn đã tìm thấy rò rỉ bộ nhớ ở đâu đó trên trang web. Nhưng điều này cũng rất hữu ích để xem liệu các thói quen giải phóng bộ nhớ có hoạt động với IE không.
Các kiểu tham chiếu không lưu trữ đối tượng trực tiếp vào biến được gán, vì vậy biến đối tượng trong ví dụ này không thực sự chứa đối tượng. Thay vào đó, nó giữ một con trỏ (hoặc tham chiếu) đến vị trí trong bộ nhớ nơi đối tượng tồn tại
var object = new Object();
nếu bạn gán một biến cho một biến khác, mỗi biến sẽ có một bản sao của con trỏ và cả hai vẫn tham chiếu cùng một đối tượng trong bộ nhớ.
var object1 = new Object();
var object2 = object1;
JavaScript là ngôn ngữ được thu gom rác , vì vậy bạn không thực sự cần phải lo lắng về việc phân bổ bộ nhớ khi bạn sử dụng các loại tham chiếu. Tuy nhiên, cách tốt nhất để tới đích của các đối tượng mà bạn không còn cần để các nhà sưu tập rác có thể giải phóng bộ nhớ. Cách tốt nhất để làm điều này là đặt biến đối tượng thành null.
var object1 = new Object();
// do something
object1 = null; // dereference
Các đối tượng hội nghị đặc biệt quan trọng trong các ứng dụng rất lớn sử dụng hàng triệu đối tượng.
từ các nguyên tắc của JavaScript hướng đối tượng - NICHOLAS C. ZAKAS