Tìm hiểu cách ghi lại ảnh chụp nhanh của vùng nhớ khối xếp bằng Bộ nhớ > Hồ sơ > Tổng quan nhanh về vùng nhớ khối xếp và tìm lỗi rò rỉ bộ nhớ.
Trình phân tích vùng nhớ khối xếp cho thấy mức phân phối bộ nhớ theo các đối tượng JavaScript của trang và các nút DOM có liên quan. Sử dụng công cụ này để chụp nhanh vùng nhớ khối xếp JS, phân tích biểu đồ bộ nhớ, so sánh ảnh chụp nhanh và tìm lỗi rò rỉ bộ nhớ. Để biết thêm thông tin, hãy xem phần Cây giữ lại đối tượng.
Chụp nhanh
Cách chụp ảnh nhanh vùng nhớ khối xếp:
- Trên trang mà bạn muốn phân tích, hãy mở Công cụ cho nhà phát triển rồi chuyển đến bảng điều khiển Bộ nhớ.
- Chọn loại hồ sơ Bản tổng quan nhanh về vùng nhớ khối xếp, sau đó chọn một thực thể máy ảo JavaScript rồi nhấp vào Lấy bản tổng quan nhanh.
Khi tải và phân tích cú pháp bản tổng quan nhanh, bảng Memory (Bộ nhớ) sẽ hiện tổng kích thước của các đối tượng JavaScript có thể truy cập bên dưới tiêu đề của bản tổng quan nhanh trong phần HEAP SNAPSHOTS.
Ảnh chụp nhanh chỉ hiển thị các đối tượng từ biểu đồ bộ nhớ có thể truy cập được từ đối tượng chung. Việc chụp nhanh luôn bắt đầu bằng việc thu thập rác.
Xoá ảnh chụp nhanh
Để xoá tất cả ảnh chụp nhanh, hãy nhấp vào
Xoá tất cả trang doanh nghiệp:Xem ảnh chụp nhanh
Để kiểm tra ảnh chụp nhanh từ nhiều góc độ cho nhiều mục đích, hãy chọn một trong các chế độ xem trong trình đơn thả xuống ở trên cùng:
Xem | Nội dung | Mục đích |
---|---|---|
Tóm tắt | Các đối tượng được nhóm theo tên hàm khởi tạo. | Sử dụng công cụ này để tìm đối tượng và mức sử dụng bộ nhớ của đối tượng dựa trên loại. Hữu ích cho việc theo dõi rò rỉ DOM. |
So sánh | Sự khác biệt giữa 2 bản tổng quan nhanh. | Sử dụng hàm này để so sánh hai (hoặc nhiều) ảnh chụp nhanh, trước và sau khi thực hiện một thao tác. Xác nhận sự hiện diện và nguyên nhân gây ra sự cố rò rỉ bộ nhớ bằng cách kiểm tra delta trong bộ nhớ được giải phóng và số lượng tham chiếu. |
Phương thức chứa | Nội dung vùng nhớ khối xếp | Cung cấp thông tin chi tiết hơn về cấu trúc đối tượng và giúp phân tích các đối tượng được tham chiếu trong không gian tên toàn cục (cửa sổ) để tìm ra những đối tượng vẫn còn tồn tại. Hãy sử dụng tính năng này để phân tích trạng thái đóng và phân tích đối tượng ở cấp độ thấp. |
Số liệu thống kê | Biểu đồ hình tròn về mức phân bổ bộ nhớ | Xem kích thước thực tế của các phần bộ nhớ được phân bổ cho mã, chuỗi, mảng JS, mảng đã nhập và đối tượng hệ thống. |
Chế độ xem tóm tắt
Ban đầu, một ảnh chụp nhanh vùng nhớ khối xếp sẽ mở trong chế độ xem Summary (Tóm tắt) liệt kê Constructor (Hàm khởi tạo) trong một cột. Bạn có thể mở rộng hàm khởi tạo để xem các đối tượng mà hàm khởi tạo tạo bản sao.
Để lọc ra các hàm khởi tạo không liên quan, hãy nhập tên mà bạn muốn kiểm tra trong Bộ lọc lớp ở đầu chế độ xem Tóm tắt.
Số bên cạnh tên hàm khởi tạo cho biết tổng số đối tượng được tạo bằng hàm khởi tạo. Chế độ xem Tóm tắt cũng hiển thị các cột sau:
- Khoảng cách cho biết khoảng cách đến gốc bằng cách sử dụng đường dẫn đơn giản ngắn nhất của các nút.
- Kích thước nông cho biết tổng kích thước nông của tất cả đối tượng do một hàm khởi tạo nhất định tạo ra. Kích thước nông là kích thước bộ nhớ mà chính đối tượng giữ. Nhìn chung, các mảng và chuỗi có kích thước nông lớn hơn. Xem thêm phần Kích thước đối tượng.
- Kích thước được giữ lại cho biết kích thước được giữ lại tối đa trong cùng một nhóm đối tượng. Dung lượng được giữ lại là dung lượng bộ nhớ mà bạn có thể giải phóng bằng cách xoá một đối tượng và làm cho các phần phụ thuộc của đối tượng đó không còn truy cập được. Xem thêm phần Kích thước đối tượng.
Khi bạn mở rộng một hàm khởi tạo, chế độ xem Tóm tắt sẽ cho bạn thấy tất cả các thực thể của hàm đó. Mỗi thực thể sẽ nhận được bảng chi tiết về kích thước nông và kích thước được giữ lại trong các cột tương ứng. Số sau ký tự @
là mã nhận dạng duy nhất của đối tượng. Tính năng này cho phép bạn so sánh ảnh chụp nhanh vùng nhớ khối xếp trên cơ sở mỗi đối tượng.
Bộ lọc hàm khởi tạo
Chế độ xem Tóm tắt cho phép bạn lọc hàm khởi tạo dựa trên các trường hợp phổ biến về việc sử dụng bộ nhớ không hiệu quả.
Để sử dụng các bộ lọc này, hãy chọn một trong các tuỳ chọn sau trong trình đơn thả xuống ở ngoài cùng bên phải trong thanh thao tác:
- Tất cả đối tượng: tất cả đối tượng được chụp bằng ảnh chụp nhanh hiện tại. Được đặt theo mặc định.
- Đối tượng được phân bổ trước bản tổng quan nhanh 1: các đối tượng đã được tạo và vẫn còn trong bộ nhớ trước khi bản tổng quan nhanh đầu tiên được chụp.
- Các đối tượng được phân bổ giữa Ảnh chụp nhanh 1 và Ảnh chụp nhanh 2: xem sự khác biệt về đối tượng giữa ảnh chụp nhanh gần đây nhất và ảnh chụp nhanh trước đó. Mỗi ảnh chụp nhanh mới sẽ thêm số lượng bộ lọc này vào danh sách thả xuống.
- Chuỗi bị trùng lặp: các giá trị chuỗi đã được lưu trữ nhiều lần trong bộ nhớ.
- Các đối tượng được các nút đã tách giữ lại: các đối tượng được duy trì hoạt động vì một nút DOM đã tách tham chiếu đến các đối tượng đó.
- Đối tượng mà bảng điều khiển Công cụ cho nhà phát triển giữ lại: các đối tượng được giữ lại trong bộ nhớ vì chúng được đánh giá hoặc tương tác thông qua bảng điều khiển Công cụ cho nhà phát triển.
Mục nhập đặc biệt trong phần Tóm tắt
Ngoài việc nhóm theo hàm khởi tạo, chế độ xem Tóm tắt cũng nhóm các đối tượng theo:
- Các hàm tích hợp sẵn như
Array
hoặcObject
. - Các phần tử HTML được nhóm theo thẻ, ví dụ:
<div>
,<a>
,<img>
và các phần tử khác. - Các hàm bạn đã xác định trong mã.
- Các danh mục đặc biệt không dựa trên hàm khởi tạo.
(array)
Danh mục này bao gồm nhiều đối tượng giống mảng nội bộ không trực tiếp tương ứng với các đối tượng hiển thị trong JavaScript.
Ví dụ: nội dung của các đối tượng Array
JavaScript được lưu trữ trong đối tượng nội bộ phụ có tên là (object elements)[]
, để cho phép đổi kích thước dễ dàng hơn. Tương tự, các thuộc tính được đặt tên trong đối tượng JavaScript thường được lưu trữ trong các đối tượng nội bộ phụ có tên là (object properties)[]
. Các đối tượng này cũng được liệt kê trong danh mục (array)
.
(compiled code)
Danh mục này bao gồm dữ liệu nội bộ mà V8 cần để có thể chạy các hàm do JavaScript hoặc WebAssembly xác định. Mỗi hàm có thể được biểu thị theo nhiều cách, từ nhỏ và chậm đến lớn và nhanh.
V8 tự động quản lý mức sử dụng bộ nhớ trong danh mục này. Nếu một hàm chạy nhiều lần, V8 sẽ sử dụng nhiều bộ nhớ hơn cho hàm đó để hàm có thể chạy nhanh hơn. Nếu một hàm không chạy trong một thời gian, V8 có thể xoá dữ liệu nội bộ cho hàm đó.
(concatenated string)
Khi nối hai chuỗi, chẳng hạn như với toán tử +
của JavaScript, V8 có thể chọn biểu thị kết quả nội bộ dưới dạng "chuỗi nối" còn gọi là cấu trúc dữ liệu Rope.
Thay vì sao chép tất cả ký tự của 2 chuỗi nguồn vào một chuỗi mới, V8 phân bổ một đối tượng nhỏ có các trường nội bộ có tên là first
và second
trỏ đến 2 chuỗi nguồn. Điều này cho phép V8 tiết kiệm thời gian và bộ nhớ. Về khía cạnh mã JavaScript, đây chỉ là các chuỗi thông thường và hoạt động giống như mọi chuỗi khác.
InternalNode
Danh mục này đại diện cho các đối tượng được phân bổ bên ngoài V8, chẳng hạn như các đối tượng C++ do Blink xác định.
Để xem tên lớp C++, hãy sử dụng Chrome for Testing (Chrome cho kiểm thử) và làm như sau:
- Mở DevTools rồi bật Settings (Cài đặt) > Experiments (Thử nghiệm) > Show option to expose internals in heap snapshots (Hiện tuỳ chọn để hiển thị nội dung bên trong trong ảnh chụp nhanh vùng nhớ khối xếp).
- Mở bảng điều khiển Memory (Bộ nhớ), chọn Heap snapshot (Bản tổng quan nhanh về vùng nhớ khối xếp) rồi bật Expose internals (includes additional implementation-specific details) (Hiện dữ liệu nội bộ (bao gồm thông tin bổ sung liên quan đến việc triển khai)).
- Tái hiện vấn đề khiến
InternalNode
giữ lại nhiều bộ nhớ. - Chụp ảnh chụp nhanh của vùng nhớ khối xếp. Trong ảnh chụp nhanh này, các đối tượng có tên lớp C++ thay vì
InternalNode
.
(object shape)
Như mô tả trong phần Thuộc tính nhanh trong V8, V8 theo dõi các lớp ẩn (hoặc hình dạng) để có thể trình bày hiệu quả nhiều đối tượng có cùng thuộc tính theo cùng một thứ tự. Danh mục này chứa các lớp ẩn đó, được gọi là system / Map
(không liên quan đến JavaScript Map
) và dữ liệu liên quan.
(sliced string)
Khi V8 cần lấy một chuỗi con, chẳng hạn như khi mã JavaScript gọi String.prototype.substring()
, V8 có thể chọn phân bổ đối tượng chuỗi được cắt thay vì sao chép tất cả các ký tự có liên quan từ chuỗi gốc. Đối tượng mới này chứa một con trỏ đến chuỗi gốc và mô tả khoảng ký tự cần sử dụng trong chuỗi ban đầu.
Từ quan điểm của mã JavaScript, đây chỉ là các chuỗi thông thường và hoạt động giống như mọi chuỗi khác. Nếu một chuỗi đã cắt đang giữ lại nhiều bộ nhớ, thì chương trình có thể đã kích hoạt Vấn đề 2869 và có thể sẽ có lợi nếu bạn thực hiện các bước có chủ ý để "làm phẳng" chuỗi đã cắt.
system / Context
Các đối tượng nội bộ thuộc loại system / Context
chứa các biến cục bộ từ một hàm đóng – một phạm vi JavaScript mà hàm lồng nhau có thể truy cập.
Mỗi thực thể hàm chứa một con trỏ nội bộ đến Context
mà hàm đó thực thi để có thể truy cập vào các biến đó. Mặc dù các đối tượng Context
không hiển thị trực tiếp từ JavaScript, nhưng bạn có quyền kiểm soát trực tiếp đối với các đối tượng đó.
(system)
Danh mục này chứa nhiều đối tượng nội bộ (chưa) được phân loại theo cách có ý nghĩa hơn.
Chế độ xem so sánh
Chế độ xem So sánh cho phép bạn tìm các đối tượng bị rò rỉ bằng cách so sánh nhiều ảnh chụp nhanh với nhau. Ví dụ: khi thực hiện một thao tác và đảo ngược thao tác đó, chẳng hạn như mở và đóng một tài liệu, bạn không được để lại các đối tượng thừa.
Cách xác minh rằng một thao tác nhất định không tạo ra sự cố rò rỉ:
- Chụp ảnh chụp nhanh vùng nhớ khối xếp trước khi thực hiện một thao tác.
- Thực hiện một thao tác. Tức là tương tác với một trang theo cách mà bạn cho rằng có thể gây ra rò rỉ.
- Thực hiện một thao tác đảo ngược. Tức là thực hiện tương tác ngược lại và lặp lại một vài lần.
- Chụp ảnh chụp nhanh vùng nhớ khối xếp thứ hai và thay đổi chế độ xem thành So sánh, so sánh ảnh chụp nhanh này với Ảnh chụp nhanh 1.
Chế độ xem So sánh cho thấy sự khác biệt giữa hai ảnh chụp nhanh. Khi mở rộng mục nhập tổng, các thực thể đối tượng đã thêm và đã xoá sẽ xuất hiện:
Khung hiển thị vùng chứa
Chế độ xem Containment (Phạm vi chứa) là "tổng quan từ trên cao" về cấu trúc đối tượng của ứng dụng. Công cụ này cho phép bạn xem bên trong các hàm đóng, quan sát các đối tượng nội bộ của máy ảo cùng tạo thành các đối tượng JavaScript, đồng thời nắm được mức sử dụng bộ nhớ mà ứng dụng của bạn sử dụng ở cấp rất thấp.
Thành phần hiển thị này cung cấp một số điểm truy cập:
- Đối tượng DOMWindow. Đối tượng toàn cầu cho mã JavaScript.
- GC gốc. Rễ GC mà bộ thu gom rác của máy ảo sử dụng. Gốc GC có thể bao gồm sơ đồ đối tượng tích hợp sẵn, bảng biểu tượng, ngăn xếp luồng máy ảo, bộ nhớ đệm biên dịch, phạm vi xử lý và tay điều khiển chung.
- Đối tượng gốc. Đối tượng trình duyệt "được đẩy" vào bên trong máy ảo JavaScript để cho phép tự động hoá, ví dụ: nút DOM và quy tắc CSS.
Mục Đường dẫn giữ lại
Phần Retainers (Giữ lại) ở cuối bảng điều khiển Memory (Bộ nhớ) cho thấy các đối tượng trỏ đến đối tượng đã chọn trong thành phần hiển thị. Bảng điều khiển Memory (Bộ nhớ) sẽ cập nhật mục Retainers (Giữ lại) khi bạn chọn một đối tượng khác trong bất kỳ chế độ xem nào ngoại trừ Statistics (Thống kê).
Trong ví dụ này, thuộc tính x
của thực thể Item
sẽ giữ lại chuỗi đã chọn.
Bỏ qua trình lưu giữ
Bạn có thể ẩn các đối tượng giữ lại để tìm hiểu xem có đối tượng nào khác giữ lại đối tượng đã chọn hay không. Với tuỳ chọn này, trước tiên, bạn không cần xoá phần giữ lại này khỏi mã rồi chụp lại ảnh chụp nhanh vùng nhớ khối xếp.
Để ẩn trình lưu giữ, hãy nhấp chuột phải và chọn Bỏ qua trình lưu giữ này. Những thành phần lưu giữ bị bỏ qua được đánh dấu là ignored
trong cột Khoảng cách. Để ngừng bỏ qua tất cả phần giữ lại, hãy nhấp vào Khôi phục phần giữ lại bị bỏ qua trong thanh thao tác ở trên cùng.
Tìm một đối tượng cụ thể
Để tìm một đối tượng trong vùng nhớ khối xếp được thu thập, bạn có thể tìm kiếm bằng tổ hợp phím Ctrl + F rồi nhập mã đối tượng.
Đặt tên cho các hàm để phân biệt các bao đóng
Việc đặt tên cho các hàm sẽ giúp bạn phân biệt được các hàm đóng trong ảnh chụp nhanh.
Ví dụ: Mã sau đây không sử dụng các hàm được đặt tên:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function() { // this is NOT a named function
return largeStr;
};
return lC;
}
Trong khi ví dụ này thì không:
function createLargeClosure() {
var largeStr = new Array(1000000).join('x');
var lC = function lC() { // this IS a named function
return largeStr;
};
return lC;
}
Phát hiện rò rỉ DOM
Trình phân tích vùng nhớ khối xếp có khả năng phản ánh các phần phụ thuộc hai chiều giữa đối tượng gốc của trình duyệt (nút DOM và quy tắc CSS) và đối tượng JavaScript. Điều này giúp phát hiện các sự cố rò rỉ không nhìn thấy được xảy ra do các cây con DOM bị tách rời bị quên trôi nổi xung quanh.
Rò rỉ DOM có thể lớn hơn bạn nghĩ. Hãy xem ví dụ sau đây. Khi nào rác #tree
được thu thập?
var select = document.querySelector;
var treeRef = select("#tree");
var leafRef = select("#leaf");
var body = select("body");
body.removeChild(treeRef);
//#tree can't be GC yet due to treeRef
treeRef = null;
//#tree can't be GC yet due to indirect
//reference from leafRef
leafRef = null;
//#NOW #tree can be garbage collected
#leaf
duy trì tham chiếu đến phần tử mẹ (parentNode
) và đệ quy đến #tree
, vì vậy, chỉ khi leafRef
bị rỗng mới là cây toàn bộ trong #tree
là một đề xuất cho GC.