Phần này mô tả các thuật ngữ phổ biến dùng trong việc phân tích bộ nhớ và có thể áp dụng cho nhiều công cụ phân tích bộ nhớ cho nhiều ngôn ngữ.
Các thuật ngữ và khái niệm được mô tả ở đây đề cập đến Trình phân tích vùng nhớ khối xếp trong Công cụ của Chrome cho nhà phát triển. Nếu bạn từng dùng trình phân tích bộ nhớ Java, .NET hoặc một số trình phân tích bộ nhớ khác, thì bạn có thể sẽ ôn lại kiến thức.
Kích thước đối tượng
Hãy xem bộ nhớ như một biểu đồ gồm các loại nguyên hàm (như số và chuỗi) và đối tượng (các mảng liên kết). Nó có thể được biểu diễn dưới dạng biểu đồ với một số điểm được kết nối như sau:
Một đối tượng có thể lưu giữ bộ nhớ theo 2 cách:
- Trực tiếp thông qua chính đối tượng đó.
- Theo cách ngầm ẩn, bằng cách giữ các tham chiếu đến các đối tượng khác, từ đó ngăn các đối tượng đó tự động bị trình thu gom rác xử lý (gọi tắt là GC).
Khi làm việc với Trình phân tích vùng nhớ khối xếp trong Công cụ cho nhà phát triển (một công cụ để điều tra các vấn đề về bộ nhớ trong phần "Hồ sơ"), có thể bạn sẽ phải xem một vài cột thông tin. Hai kích thước nổi bật là Kích thước của đối tượng và Kích thước giữ nguyên, nhưng những thông tin này thể hiện điều gì?
Kích thước của đối tượng
Đây là dung lượng bộ nhớ do chính đối tượng lưu giữ.
Các đối tượng JavaScript điển hình có một số bộ nhớ dành riêng cho phần mô tả và để lưu trữ các giá trị tức thì. Thông thường, chỉ các mảng và chuỗi mới có thể có kích thước nông đáng kể. Tuy nhiên, các chuỗi và mảng bên ngoài thường có bộ nhớ chính trong bộ nhớ kết xuất, chỉ hiển thị một đối tượng trình bao bọc nhỏ trên vùng nhớ khối xếp JavaScript.
Bộ nhớ trình kết xuất là toàn bộ bộ nhớ của quy trình hiển thị trang được kiểm tra: bộ nhớ gốc + bộ nhớ vùng nhớ khối xếp JS của trang + bộ nhớ vùng nhớ khối xếp JS của tất cả worker chuyên dụng được bắt đầu trên trang. Tuy nhiên, ngay cả một đối tượng nhỏ cũng có thể gián tiếp giữ một dung lượng lớn bộ nhớ, bằng cách ngăn các đối tượng khác bị quá trình thu gom rác tự động loại bỏ.
Kích thước được giữ lại
Đây là dung lượng bộ nhớ được giải phóng sau khi chính đối tượng bị xoá cùng với các đối tượng phụ thuộc mà gốc GC không thể tiếp cận được.
Gốc GC bao gồm các xử lý được tạo (cục bộ hoặc toàn cục) khi tham chiếu từ mã gốc đến một đối tượng JavaScript bên ngoài V8. Bạn có thể tìm thấy tất cả các tên người dùng như vậy trong ảnh chụp nhanh của vùng nhớ khối xếp trong Gốc GC > Phạm vi xử lý và Gốc GC > Xử lý chung. Việc mô tả tên người dùng trong tài liệu này mà không đi sâu vào chi tiết về cách triển khai trình duyệt có thể gây nhầm lẫn. Bạn không cần phải lo lắng về cả gốc GC và tay điều khiển.
Có rất nhiều gốc GC nội bộ hầu hết đều không khiến người dùng thấy hứng thú. Xét trên quan điểm ứng dụng, có các loại gốc sau:
- Đối tượng chung cho cửa sổ (trong mỗi iframe). Có một trường khoảng cách trong ảnh chụp nhanh của vùng nhớ khối xếp. Đó là số lượng tham chiếu thuộc tính trên đường dẫn giữ lại ngắn nhất từ cửa sổ.
- Cây DOM tài liệu bao gồm tất cả các nút DOM gốc có thể truy cập được bằng cách truyền tải tài liệu. Không phải tất cả các trình bao bọc này đều có trình bao bọc JS, nhưng nếu trình bao bọc đó vẫn tồn tại thì tài liệu vẫn tồn tại.
- Đôi khi, các đối tượng có thể được giữ lại theo ngữ cảnh của trình gỡ lỗi và bảng điều khiển Công cụ cho nhà phát triển (ví dụ: sau khi đánh giá bảng điều khiển). Tạo ảnh chụp nhanh vùng nhớ khối xếp với bảng điều khiển rõ ràng và không có điểm ngắt đang hoạt động trong trình gỡ lỗi.
Biểu đồ bộ nhớ bắt đầu bằng một gốc, có thể là đối tượng window
của trình duyệt hoặc đối tượng Global
của mô-đun Node.js. Bạn không thể kiểm soát cách GC'd đối tượng gốc này.
Bất kỳ nội dung nào không truy cập được từ gốc sẽ nhận được GC.
Cây giữ lại đối tượng
Vùng nhớ khối xếp là một mạng lưới các đối tượng liên kết với nhau. Trong thế giới toán học, cấu trúc này được gọi là đồ thị hoặc biểu đồ bộ nhớ. Một biểu đồ được tạo từ các nút được kết nối bằng cạnh, cả hai đều được gán nhãn.
- Các nút (hoặc đối tượng) được gắn nhãn bằng tên của hàm hàm khởi tạo dùng để tạo các nút đó.
- Các cạnh được gắn nhãn bằng tên của thuộc tính.
Tìm hiểu cách ghi lại hồ sơ bằng Trình phân tích vùng nhớ khối xếp. Một số điều bắt mắt mà chúng ta có thể thấy trong bản ghi của Trình phân tích vùng nhớ khối xếp dưới đây bao gồm khoảng cách: khoảng cách từ gốc GC. Nếu gần như tất cả các đối tượng cùng loại ở cùng khoảng cách và một số đối tượng ở khoảng cách lớn hơn, thì đó là điều đáng kiểm tra.
Người thống trị
Đối tượng phần tử chiếm ưu thế bao gồm cấu trúc cây vì mỗi đối tượng chỉ có đúng một phần tử chiếm ưu thế. Phần tử ưu tiên của một đối tượng có thể thiếu thông tin tham chiếu trực tiếp đến đối tượng mà nó thống trị; nghĩa là cây của đối tượng thống trị không phải là cây bao trùm của biểu đồ.
Trong biểu đồ dưới đây:
- Nút 1 chiếm ưu thế nút 2
- Nút 2 chi phối các nút 3, 4 và 6
- Nút 3 chi phối nút 5
- Nút 5 chi phối nút 8
- Nút 6 chi phối nút 7
Trong ví dụ bên dưới, nút #3
là nút chi phối của #10
, nhưng #7
cũng tồn tại trong mọi đường dẫn đơn giản từ GC đến #10
. Do đó, một đối tượng B là đối tượng chiếm ưu thế của đối tượng A nếu B tồn tại trong mọi đường dẫn đơn giản từ gốc đến đối tượng A.
Thông tin cụ thể về V8
Khi phân tích bộ nhớ, bạn nên tìm hiểu lý do khiến ảnh chụp nhanh vùng nhớ khối xếp có một cách nhất định. Phần này mô tả một số chủ đề liên quan đến bộ nhớ cụ thể tương ứng với máy ảo V8 JavaScript (máy ảo V8 hoặc máy ảo).
Biểu diễn đối tượng JavaScript
Có 3 kiểu dữ liệu nguyên gốc:
- Số (ví dụ: 3,14159..)
- Boolean (đúng hoặc sai)
- Chuỗi (ví dụ: "Werner Heisenberg")
Chúng không thể tham chiếu các giá trị khác và luôn là lá hoặc nút kết thúc.
Bạn có thể lưu trữ số dưới dạng:
- một giá trị số nguyên 31 bit tức thì được gọi là số nguyên nhỏ (SMI), hoặc
- đối tượng vùng nhớ khối xếp, được gọi là số vùng nhớ khối xếp. Số vùng nhớ khối xếp được dùng để lưu trữ các giá trị không phù hợp với biểu mẫu SMI, chẳng hạn như doubles hoặc khi một giá trị cần được đóng hộp, chẳng hạn như đặt thuộc tính trên đó.
Bạn có thể lưu trữ Chuỗi trong:
- vùng nhớ khối xếp máy ảo hoặc
- bên ngoài vào bộ nhớ của trình kết xuất. Một đối tượng trình bao bọc được tạo và dùng để truy cập vào bộ nhớ ngoài, nơi lưu trữ các nguồn tập lệnh và nội dung khác nhận được từ Web, thay vì được sao chép vào vùng nhớ khối xếp ảo.
Bộ nhớ cho các đối tượng JavaScript mới được phân bổ từ một vùng nhớ khối xếp JavaScript chuyên dụng (hoặc vùng nhớ khối xếp máy ảo). Các đối tượng này do trình thu gom rác của V8 quản lý nên sẽ vẫn tồn tại miễn là có ít nhất một tệp tham chiếu rõ ràng đến các đối tượng đó.
Đối tượng gốc là mọi nội dung khác không có trong vùng nhớ khối xếp JavaScript. Đối tượng gốc, trái ngược với đối tượng vùng nhớ khối xếp, không được trình thu thập rác V8 quản lý trong suốt thời gian hoạt động và chỉ có thể truy cập được qua JavaScript bằng đối tượng trình bao bọc JavaScript của đối tượng này.
Chuỗi Nhược điểm là một đối tượng bao gồm các cặp chuỗi được lưu trữ sau đó kết hợp và là kết quả của việc nối. Việc kết hợp nội dung chuỗi cons chỉ diễn ra khi cần. Ví dụ như khi cần tạo chuỗi con của chuỗi đã kết hợp.
Ví dụ: nếu nối a và b, bạn sẽ nhận được một chuỗi (a, b) đại diện cho kết quả nối. Nếu sau đó bạn đã nối d với kết quả đó, bạn sẽ nhận được một chuỗi cons khác ((a, b), d).
Mảng – Mảng là một Đối tượng có các khoá số. Các API này được sử dụng rộng rãi trong máy ảo V8 để lưu trữ một lượng lớn dữ liệu. Tập hợp các cặp khoá-giá trị được dùng như từ điển được sao lưu bằng các mảng.
Đối tượng JavaScript thông thường có thể là một trong hai loại mảng được dùng để lưu trữ:
- các thuộc tính có tên
- phần tử số
Trong trường hợp có rất ít thuộc tính, các thuộc tính đó có thể được lưu trữ nội bộ trong chính đối tượng JavaScript.
Bản đồ – một đối tượng mô tả loại đối tượng và bố cục của đối tượng đó. Ví dụ: bản đồ được dùng để mô tả hệ phân cấp đối tượng ngầm ẩn giúp truy cập nhanh vào thuộc tính.
Nhóm đối tượng
Mỗi nhóm đối tượng gốc được tạo thành từ các đối tượng có tham chiếu lẫn nhau. Ví dụ: hãy xem xét một cây con DOM, trong đó mỗi nút đều có một đường liên kết đến nút mẹ và liên kết với cây con tiếp theo cũng như nút đồng cấp tiếp theo, từ đó tạo thành một biểu đồ liên kết. Lưu ý rằng các đối tượng gốc không được biểu thị trong vùng nhớ khối xếp JavaScript. Đó là lý do các đối tượng này có kích thước bằng 0. Thay vào đó, các đối tượng trình bao bọc sẽ được tạo.
Mỗi đối tượng trình bao bọc chứa một tham chiếu đến đối tượng gốc tương ứng để chuyển hướng các lệnh đến đối tượng đó. Đến lượt mình, một nhóm đối tượng sẽ giữ các đối tượng trình bao bọc. Tuy nhiên, điều này không tạo ra một chu kỳ không thể thu thập, vì GC đủ thông minh để giải phóng các nhóm đối tượng có trình bao bọc không còn được tham chiếu nữa. Tuy nhiên, nếu bạn quên phát hành một trình bao bọc, thì toàn bộ nhóm và các trình bao bọc liên kết sẽ được giữ lại.