Ghi lại ảnh chụp nhanh của vùng nhớ khối xếp

Meggin Kearney
Meggin Kearney
Sofia Emelianova
Sofia Emelianova

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ơ > Ảnh chụp nhanh của 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 hiển thị sự phân phối bộ nhớ theo đối tượng JavaScript của trang và các nút DOM có liên quan. Hãy sử dụng công cụ này để chụp ảnh 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 bài viết Cây giữ lại đối tượng.

Chụp nhanh

Cách chụp nhanh vùng nhớ khối xếp:

  1. Trên trang bạn muốn định cấu hình, 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ớ.
  2. Chọn loại lập hồ sơ radio_button_checked Heap snapshot (Ảnh chụp nhanh của 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 Take snapshot (Tạo ảnh chụp nhanh).

Một loại lập hồ sơ và thực thể máy ảo JavaScript đã chọn.

Khi tải và phân tích cú pháp ảnh chụp nhanh, bảng điều khiển Memory (Bộ nhớ) sẽ hiển thị 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 đề ảnh chụp nhanh trong phần HEAP SNAPSHOTS.

Tổng kích thước của các đối tượng có thể truy cập.

Ảnh chụp nhanh chỉ cho thấy các đối tượng trong biểu đồ bộ nhớ có thể truy cập được qua đối tượng chung. Quá trình chụp ảnh nhanh luôn bắt đầu từ việc thu thập rác.

Ảnh chụp nhanh của vùng nhớ khối xếp gồm các đối tượng Item phân tán.

Xoá ảnh chụp nhanh

Để xoá tất cả ảnh chụp nhanh, hãy nhấp vào chặn Xoá tất cả hồ sơ:

Xoá tất cả hồ sơ.

Xem ảnh chụp nhanh

Để kiểm tra ảnh chụp nhanh từ nhiều góc nhìn cho nhiều mục đích, hãy chọn một trong các chế độ xem từ 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. Hãy dùng thư viện này để săn lùng đối tượng và mức sử dụng bộ nhớ dựa trên loại. Hữu ích để theo dõi rò rỉ DOM.
So sánh Sự khác biệt giữa hai ảnh chụp nhanh. Sử dụng trình đơn này để so sánh hai (hoặc nhiều) ảnh chụp nhanh trước và sau 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ớ đã giải phóng và số lượng tham chiếu.
Vùng chứa Nội dung của vùng nhớ khối xếp Mang đến cái nhìn rõ hơn về cấu trúc đối tượng, đồng thời giúp phân tích các đối tượng được tham chiếu trong không gian tên chung (cửa sổ) để tìm ra nội dung giữ các đối tượng đó. Hãy sử dụng tính năng này để phân tích vùng đóng cửa và phân tích chi tiết các đối tượng của bạn ở cấp độ thấp.
Số liệu thống kê Biểu đồ hình tròn về quy trình phân bổ bộ nhớ Xem kích thước thực 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 được chọn từ trình đơn thả xuống ở trên cùng.

Chế độ xem tóm tắt

Ban đầu, ảnh chụp nhanh của vùng nhớ khối xếp sẽ mở trong chế độ xem Tóm tắt, liệt kê Hàm khởi tạo trong một cột. Bạn có thể mở rộng các hàm khởi tạo để xem các đối tượng mà các hàm đó đã tạo thực thể.

Khung hiển thị Summary (Tóm tắt) có một hàm khởi tạo được mở rộng.

Để 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.

Các con 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 của đối tượng cho biết tổng kích thước 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 của bộ nhớ do chính một đối tượng giữ lại. Các mảng và chuỗi thường có kích thước nông lớn hơn. Hãy xem thêm mục Kích thước đối tượng.
  • Kích thước được giữ lại cho biết kích thước tối đa được giữ lại giữa cùng một nhóm đối tượng. Kích thước đượ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à xoá bỏ các phần phụ thuộc của đối tượng đó. Hãy xem thêm mục Kích thước đối tượng.

Khi bạn mở rộng một hàm khởi tạo, khung hiển thị summary (Tóm tắt) sẽ cho bạn thấy tất cả thực thể của hàm khởi tạo đó. Mỗi phiên bản đều 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. API này cho phép bạn so sánh ảnh chụp nhanh của vùng nhớ khối xếp trên cơ sở từng đối tượng.

Các mục nhập đặc biệt trong phần Tóm tắt

Ngoài việc nhóm theo hàm dựng, chế độ xem Tóm tắt còn nhóm các đối tượng theo:

  • Các hàm tích hợp như Array hoặc Object.
  • 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 dựng.

Mục nhập của hàm khởi tạo.

(array)

Danh mục này bao gồm nhiều đối tượng nội bộ giống như mảng không tương ứng trực tiếp với các đối tượng hiển thị trong JavaScript.

Ví dụ: nội dung của các đối tượng JavaScript Array được lưu trữ trong một đố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 thuộc tính này cũng có tên 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 khác nhau, 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 đó để 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ộ của hàm đó.

(concatenated string)

Khi V8 nối hai chuỗi (ví dụ: với toán tử + của JavaScript), công cụ này có thể chọn biểu thị kết quả trong nội bộ dưới dạng một "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ỏ với các trường nội bộ có tên là firstsecond, 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ớ. Từ góc độ của mã JavaScript, đây chỉ là các chuỗi thông thường và chúng hoạt động giống như bất kỳ chuỗi nào 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ư đối tượng C++ do Blink xác định.

Để xem tên lớp C++, hãy dùng Chrome for Testing và làm như sau:

  1. Mở Công cụ cho nhà phát triển rồi bật phần cài đặt Cài đặt > Thử nghiệm > check_box Hiển thị tuỳ chọn để hiển thị nội bộ trong ảnh chụp nhanh của vùng nhớ khối xếp.
  2. Mở bảng điều khiển Memory (Bộ nhớ), chọn radio_button_checked Ảnh chụp nhanh của vùng nhớ khối xếp rồi bật check_box Hiển thị các thành phần bên trong (bao gồm cả thông tin chi tiết bổ sung theo cách triển khai cụ thể).
  3. Tái hiện sự cố khiến InternalNode giữ lại nhiều bộ nhớ.
  4. Chụp nhanh 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 (hay hình dạng) để có thể biểu thị nhiều đối tượng có cùng thuộc tính theo cùng một thứ tự một cách hiệu quả. 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 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ắt lát thay vì sao chép tất cả ký tự có liên quan trong chuỗi ban đầu. Đối tượng mới này chứa một con trỏ đến chuỗi gốc và mô tả dải ký tự cần sử dụng trong chuỗi gốc.

Từ góc độ của mã JavaScript, đây chỉ là các chuỗi thông thường và chúng hoạt động giống như bất kỳ chuỗi nào 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ể hưởng lợi từ việc thực hiện các bước có chủ ý để "làm phẳng" chuỗi đã được cắt lá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 trạng thái đóng – một phạm vi JavaScript mà hàm lồng nhau có thể truy cập.

Mỗi thực thể của hàm đều chứa một con trỏ nội bộ đến Context mà nó 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 qua JavaScript, nhưng bạn có quyền kiểm soát trực tiếp đối với các đối tượng này.

(system)

Danh mục này chứa nhiều đối tượng nội bộ khác nhau chưa (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, chẳng hạn như mở và đóng một tài liệu, bạn sẽ không để lại đối tượng thừa.

Cách xác minh rằng một hoạt động nhất định không tạo ra sự cố rò rỉ:

  1. Hãy chụp ảnh vùng nhớ khối xếp trước khi thực hiện thao tác.
  2. Thực hiện một thao tác. Tức là tương tác với trang theo cách nào đó mà bạn cho là có thể gây ra rò rỉ.
  3. Thực hiện thao tác đảo ngược. Tức là, thực hiện hành động tương tác ngược lại và lặp lại vài lần.
  4. Chụp ảnh nhanh vùng nhớ khối xếp thứ hai và thay đổi chế độ xem thành So sánh, so sánh 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 tổng số mục, bạn sẽ thấy các thực thể đối tượng đã thêm và đã xoá:

So sánh với Ảnh chụp nhanh 1.

Chế độ xem vùng chứa

Chế độ xem Vùng chứa là "chế độ xem toàn cảnh" về cấu trúc đối tượng của ứng dụng. Công cụ này cho phép bạn xem nhanh các hàm bị đóng, quan sát các đối tượng bên trong máy ảo cùng tạo thành các đối tượng JavaScript của bạn, cũng như biết được mức sử dụng bộ nhớ của ứng dụng ở cấp rất thấp.

Chế độ xem này cung cấp một số điểm truy cập:

  • Đối tượng DOMWindow. Đối tượng chung cho mã JavaScript.
  • Gốc GCC. Các gốc GC mà bộ thu gom rác của máy ảo sử dụng. Gốc GC có thể bao gồm các 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à trình xử lý chung.
  • Đối tượng gốc. Các đối tượng của trình duyệt được "đẩy" vào bên trong máy ảo JavaScript để cho phép tự động hoá, chẳng hạn như nút DOM và các quy tắc CSS.

Chế độ xem Vùng chứa.

Mục Người giữ lại

Phần Trình lưu giữ ở cuối bảng điều khiển Bộ nhớ cho thấy các đối tượng trỏ đến đối tượng đã chọn trong khung hiển thị.

Mục Người giữ lại.

Trong ví dụ này, thuộc tính x của thực thể Item sẽ giữ lại chuỗi đã chọn.

Tìm một đối tượng cụ thể

Để tìm một đối tượng trong vùng nhớ khối xếp đã 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 cửa đóng

Việc đặt tên cho các hàm sẽ giúp ích rất nhiều để bạn có thể phân biệt các trạng thái đó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ực hiện:

function createLargeClosure() {
  var largeStr = new Array(1000000).join('x');

  var lC = function lC() { // this IS a named function
    return largeStr;
  };

  return lC;
}

Hàm được đặt tên trong một hàm đóng.

Phát hiện rò rỉ dữ liệu 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 những sự cố rò rỉ dữ liệu vô hình đang xảy ra do các cây con DOM tách rời bị quên lãng lơ lửng.

Sự cố rò rỉ DOM có thể lớn hơn bạn nghĩ. Hãy xem ví dụ sau đây. Khi nào thì rác #tree được thu gom?

  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 thành phần mẹ (parentNode) và đệ quy đến #tree, vì vậy, chỉ khi leafRef bị vô hiệu hoá thì cây toàn bộ trong #tree sẽ là đề xuất cho GC.

Cây con DOM