Khắc phục sự cố về bộ nhớ

Tiếng Kayce Basques
Tiếng Basques Kayce

Tìm hiểu cách sử dụng Chrome và Công cụ cho nhà phát triển để tìm các vấn đề về bộ nhớ ảnh hưởng đến hiệu suất trang, bao gồm cả sự cố rò rỉ bộ nhớ, tình trạng đầy bộ nhớ và thu thập rác thường xuyên.

Tóm tắt

  • Tìm hiểu xem trang của bạn hiện đang sử dụng bao nhiêu bộ nhớ bằng Trình quản lý tác vụ Chrome.
  • Trực quan hoá mức sử dụng bộ nhớ theo thời gian bằng bản ghi Dòng thời gian.
  • Xác định các cây DOM tách rời (nguyên nhân phổ biến gây rò rỉ bộ nhớ) bằng Ảnh chụp nhanh vùng nhớ khối xếp.
  • Tìm hiểu thời điểm bộ nhớ mới được phân bổ trong vùng nhớ khối xếp JS của bạn bằng các bản ghi Dòng thời gian phân bổ.

Tổng quan

Theo tinh thần của mô hình hiệu suất RAIL, người dùng của bạn nên tập trung vào nỗ lực tăng hiệu suất.

Các vấn đề về bộ nhớ rất quan trọng vì người dùng thường nhận biết được các vấn đề này. Người dùng có thể nhận biết các vấn đề về bộ nhớ theo những cách sau:

  • Hiệu suất của trang ngày càng kém đi theo thời gian. Đây có thể là triệu chứng của sự cố rò rỉ bộ nhớ. Rò rỉ bộ nhớ là khi một lỗi trên trang khiến trang ngày càng sử dụng nhiều bộ nhớ hơn theo thời gian.
  • Hiệu suất của một trang liên tục kém. Đây có thể là triệu chứng của chứng đầy hơi bộ nhớ. Tăng bộ nhớ là khi một trang sử dụng nhiều bộ nhớ hơn mức cần thiết để có tốc độ trang tối ưu.
  • Hiệu suất của một trang bị chậm trễ hoặc có vẻ thường xuyên tạm dừng. Đây có thể là dấu hiệu của việc thu gom rác thường xuyên. Thu gom rác là khi trình duyệt thu hồi bộ nhớ. Trình duyệt sẽ quyết định thời điểm điều này xảy ra. Trong quá trình thu thập, tất cả quá trình thực thi tập lệnh đều bị tạm dừng. Vì vậy, nếu trình duyệt thu thập nhiều rác, quá trình thực thi tập lệnh sẽ bị tạm dừng nhiều.

Bộ nhớ đầy: mức độ "quá nhiều" là bao nhiêu?

Lỗi rò rỉ bộ nhớ rất dễ xác định. Nếu một trang web đang dần sử dụng ngày càng nhiều bộ nhớ, thì tức là bạn đã bị rò rỉ dữ liệu. Tuy nhiên, việc vượt quá giới hạn bộ nhớ lại khó xác định hơn. Điều gì được xem là "sử dụng quá nhiều bộ nhớ"?

Không có con số cố định ở đây, vì các thiết bị và trình duyệt khác nhau có khả năng khác nhau. Cùng một trang chạy mượt mà trên điện thoại thông minh cao cấp có thể gặp sự cố trên điện thoại thông minh cấp thấp.

Điều quan trọng ở đây là bạn cần sử dụng mô hình RAIL và tập trung vào người dùng của mình. Hãy tìm hiểu xem thiết bị nào phổ biến với người dùng của bạn, sau đó kiểm tra trang của bạn trên các thiết bị đó. Nếu trải nghiệm liên tục không tốt, trang có thể đang vượt quá dung lượng bộ nhớ của các thiết bị đó.

Giám sát mức sử dụng bộ nhớ theo thời gian thực bằng Trình quản lý tác vụ Chrome

Dùng Trình quản lý tác vụ Chrome làm nơi bắt đầu điều tra sự cố về bộ nhớ. Trình quản lý tác vụ là trình theo dõi theo thời gian thực, cho bạn biết mức bộ nhớ mà một trang hiện đang sử dụng.

  1. Nhấn tổ hợp phím Shift+Esc hoặc chuyển đến trình đơn chính của Chrome rồi chọn More tools (Công cụ khác) > Task manager (Trình quản lý tác vụ) để mở Trình quản lý tác vụ.

    Mở Trình quản lý tác vụ

  2. Nhấp chuột phải vào tiêu đề bảng của Trình quản lý tác vụ rồi bật bộ nhớ JavaScript.

    Bật bộ nhớ JS

Hai cột này cho bạn biết các thông tin khác nhau về cách trang của bạn đang sử dụng bộ nhớ:

  • Cột Memory (Bộ nhớ) biểu thị bộ nhớ gốc. Các nút DOM được lưu trữ trong bộ nhớ gốc. Nếu giá trị này tăng lên, thì các nút DOM đang được tạo.
  • Cột JavaScript Memory (Bộ nhớ JavaScript) đại diện cho vùng nhớ khối xếp JS. Cột này chứa hai giá trị. Giá trị bạn quan tâm là số trực tiếp (số trong ngoặc đơn). Số trực tiếp cho biết dung lượng bộ nhớ mà các đối tượng có thể truy cập trên trang đang sử dụng. Nếu con số này tăng lên, thì tức là các đối tượng mới đang được tạo hoặc các đối tượng hiện có đang tăng lên.

Trực quan hoá tình trạng rò rỉ bộ nhớ bằng Bản ghi hiệu suất

Bạn cũng có thể sử dụng bảng điều khiển Hiệu suất làm một điểm khởi đầu khác trong quá trình tìm hiểu. Bảng điều khiển Hiệu suất giúp bạn hình dung mức sử dụng bộ nhớ của trang theo thời gian.

  1. Mở bảng điều khiển Hiệu suất trên Công cụ cho nhà phát triển.
  2. Bật hộp kiểm Bộ nhớ.
  3. Tạo bản ghi âm.

Để minh hoạ bản ghi bộ nhớ Hiệu suất, hãy xem xét mã bên dưới:

var x = [];

function grow() {
  for (var i = 0; i < 10000; i++) {
    document.body.appendChild(document.createElement('div'));
  }
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Mỗi khi người dùng nhấn nút được tham chiếu trong mã, 10.000 nút div sẽ được nối vào phần nội dung tài liệu và một chuỗi gồm 1 triệu ký tự x sẽ được đẩy vào mảng x. Khi chạy mã này, bạn sẽ tạo ra bản ghi Dòng thời gian như ảnh chụp màn hình sau:

ví dụ về tăng trưởng đơn giản

Đầu tiên là phần giải thích về giao diện người dùng. Biểu đồ HEAP trong ngăn Overview (Tổng quan) (bên dưới NET) đại diện cho vùng nhớ khối xếp JS. Bên dưới ngăn Overview (Tổng quan) là ngăn Counter (Bộ đếm). Tại đây, bạn có thể thấy mức sử dụng bộ nhớ được chia nhỏ theo vùng nhớ khối xếp JS (tương tự như biểu đồ HEAP trong ngăn Overview (Tổng quan), tài liệu, nút DOM, trình nghe và bộ nhớ GPU. Khi bạn tắt hộp đánh dấu, hộp đánh dấu đó sẽ bị ẩn khỏi biểu đồ.

Bây giờ là một bản phân tích mã so với ảnh chụp màn hình. Nếu nhìn vào bộ đếm nút (biểu đồ màu xanh lục), bạn có thể thấy bộ đếm khớp hoàn toàn với mã. Số lượng nút sẽ tăng theo các bước riêng biệt. Bạn có thể giả định rằng mỗi lần tăng trong số lượng nút là một lệnh gọi đến grow(). Biểu đồ vùng nhớ khối xếp JS (biểu đồ màu xanh dương) không đơn giản. Theo các phương pháp hay nhất, điểm giảm đầu tiên thực sự là một sự kiện thu thập rác bắt buộc (đạt được bằng cách nhấn vào nút thu thập rác). Khi quá trình ghi lại diễn ra, bạn có thể thấy kích thước vùng nhớ khối xếp JS tăng đột biến. Điều này là tự nhiên và nằm trong dự kiến: mã JavaScript sẽ tạo các nút DOM trên mỗi lần nhấp vào nút và thực hiện rất nhiều việc khi tạo ra chuỗi một triệu ký tự. Điều quan trọng ở đây là trên thực tế, vùng nhớ khối xếp JS kết thúc cao hơn so với lúc bắt đầu (từ "bắt đầu" ở đây là điểm sau hoạt động thu thập rác bắt buộc). Trong thực tế, nếu bạn thấy mẫu tăng kích thước vùng nhớ khối xếp JS hoặc kích thước nút này, thì đó có thể là dấu hiệu rò rỉ bộ nhớ.

Khám phá sự cố rò rỉ bộ nhớ cây DOM tách rời thông qua Ảnh chụp nhanh vùng nhớ khối xếp

Nút DOM chỉ có thể được thu gom rác khi không có thông tin tham chiếu đến nút đó từ cây DOM hoặc mã JavaScript của trang. Một nút được xem là "tách biệt" khi bị xoá khỏi cây DOM nhưng một số JavaScript vẫn tham chiếu đến nút đó. Các nút DOM tách ra là nguyên nhân phổ biến gây ra rò rỉ bộ nhớ. Phần này hướng dẫn bạn cách sử dụng trình phân tích vùng nhớ khối xếp của Công cụ cho nhà phát triển để xác định các nút đã tách rời.

Sau đây là một ví dụ đơn giản về nút DOM tách rời.

var detachedTree;

function create() {
  var ul = document.createElement('ul');
  for (var i = 0; i < 10; i++) {
    var li = document.createElement('li');
    ul.appendChild(li);
  }
  detachedTree = ul;
}

document.getElementById('create').addEventListener('click', create);

Thao tác nhấp vào nút được tham chiếu trong mã sẽ tạo ra một nút ul có 10 li phần tử con. Các nút này được mã tham chiếu nhưng không tồn tại trong cây DOM, vì vậy chúng có thể tách ra.

Ảnh chụp nhanh của vùng nhớ khối xếp là một cách để xác định các nút đã tách rời. Đúng như tên gọi, ảnh chụp nhanh của vùng nhớ khối xếp cho bạn biết cách phân phối bộ nhớ giữa các đối tượng JS và nút DOM trên trang của bạn tại thời điểm chụp nhanh.

Để tạo ảnh chụp nhanh, hãy mở Công cụ cho nhà phát triển rồi chuyển đến bảng điều khiển Memory (Bộ nhớ), chọn nút chọn Heap Snapshot (Ảnh chụp nhanh), sau đó nhấn nút Take Snapshot (Chụp ảnh nhanh).

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

Có thể mất chút thời gian để xử lý và tải ảnh chụp nhanh. Sau khi hoàn tất, hãy chọn bảng điều khiển bên trái (có tên là HEAP SNAPSHOTS).

Nhập Detached vào hộp văn bản Class filter (Bộ lọc lớp) để tìm kiếm các cây DOM đã tách rời.

lọc tìm các nút đã tách rời

Mở rộng các biểu tượng cara để kiểm tra một cây đã tách ra.

đang điều tra cây tách rời

Các nút được đánh dấu màu vàng có thông tin tham chiếu trực tiếp đến các nút đó từ mã JavaScript. Các nút được đánh dấu màu đỏ không có tệp tham chiếu trực tiếp. Chúng chỉ còn sống vì là một phần của cây của nút màu vàng. Nói chung, bạn nên tập trung vào các nút màu vàng. Hãy sửa mã để nút màu vàng không tồn tại lâu hơn mức cần thiết, đồng thời bạn cũng loại bỏ các nút màu đỏ thuộc cây của nút màu vàng.

Nhấp vào nút màu vàng để tìm hiểu thêm. Trong ngăn Objects (Đối tượng), bạn có thể xem thêm thông tin về mã tham chiếu đến mã đó. Ví dụ: trong ảnh chụp màn hình dưới đây, bạn có thể thấy biến detachedTree đang tham chiếu đến nút. Để khắc phục tình trạng rò rỉ bộ nhớ cụ thể này, bạn cần nghiên cứu mã sử dụng detachedTree và đảm bảo rằng mã này sẽ xoá tham chiếu đến nút khi không cần dùng nữa.

điều tra nút màu vàng

Xác định tình trạng rò rỉ bộ nhớ của vùng nhớ khối xếp JS bằng tính năng Phân bổ dòng thời gian

Tiến trình phân bổ là một công cụ khác có thể giúp bạn theo dõi lỗi rò rỉ bộ nhớ trong vùng nhớ khối xếp JS của mình.

Để minh hoạ Tiến trình phân bổ, hãy xem xét mã sau:

var x = [];

function grow() {
  x.push(new Array(1000000).join('x'));
}

document.getElementById('grow').addEventListener('click', grow);

Mỗi khi nút được tham chiếu trong mã được đẩy, một chuỗi gồm 1 triệu ký tự sẽ được thêm vào mảng x.

Để ghi lại Tiến trình phân bổ, hãy mở Công cụ cho nhà phát triển, chuyển đến bảng Hồ sơ, chọn nút chọn Ghi lại tiến trình phân bổ, nhấn nút Bắt đầu, thực hiện hành động mà bạn nghi ngờ là gây ra sự cố rò rỉ bộ nhớ, sau đó nhấn nút dừng ghi (nút dừng ghi âm) khi hoàn tất.

Khi bạn ghi lại, hãy chú ý xem có thanh màu xanh dương nào xuất hiện trên Tiến trình phân bổ hay không, như trong ảnh chụp màn hình bên dưới.

lượt phân bổ mới

Các thanh màu xanh dương đó biểu thị cơ cấu phân bổ bộ nhớ mới. Các cơ cấu phân bổ bộ nhớ mới đó là đề xuất của bạn cho trường hợp rò rỉ bộ nhớ. Bạn có thể thu phóng trên một thanh để lọc ngăn Hàm khởi tạo nhằm chỉ hiển thị các đối tượng đã được phân bổ trong khung thời gian đã chỉ định.

tiến trình phân bổ thu phóng

Mở rộng đối tượng rồi nhấp vào giá trị của đối tượng đó để xem thêm thông tin chi tiết về đối tượng đó trong ngăn Object (Đối tượng). Ví dụ: trong ảnh chụp màn hình dưới đây, bằng cách xem thông tin chi tiết về đối tượng mới được phân bổ, bạn có thể thấy đối tượng đó đã được phân bổ cho biến x trong phạm vi Window.

thông tin chi tiết về đối tượng

Kiểm tra quá trình phân bổ bộ nhớ theo hàm

Dùng loại Allocation Sampling (Lấy mẫu phân bổ) trong bảng điều khiển Memory (Bộ nhớ) để xem quá trình phân bổ bộ nhớ theo hàm JavaScript.

Ghi lại Trình phân tích phân bổ

  1. Chọn nút chọn Allocation Sampling (Lấy mẫu phân bổ). Nếu có một trình thực thi trên trang, bạn có thể chọn trình chạy đó làm mục tiêu lập hồ sơ bằng cách sử dụng trình đơn thả xuống bên cạnh nút Start (Bắt đầu).
  2. Nhấn nút Start (Bắt đầu).
  3. Thực hiện các hành động trên trang mà bạn muốn điều tra.
  4. Nhấn vào nút Stop (Dừng) khi bạn đã hoàn tất tất cả các hành động.

Công cụ cho nhà phát triển hiển thị cho bạn bảng chi tiết về mức phân bổ bộ nhớ theo hàm. Chế độ xem mặc định là Nặng (Từ dưới lên), hiển thị các hàm được phân bổ nhiều bộ nhớ nhất ở trên cùng.

Hồ sơ phân bổ

Phát hiện những nơi thu gom rác thường xuyên

Nếu trang của bạn có vẻ tạm dừng thường xuyên, thì có thể bạn đang gặp vấn đề về việc thu gom rác.

Bạn có thể sử dụng Trình quản lý tác vụ của Chrome hoặc bản ghi bộ nhớ trên Dòng thời gian để phát hiện các bộ sưu tập rác thường xuyên. Trong Trình quản lý tác vụ, các giá trị Bộ nhớ hoặc Bộ nhớ JavaScript tăng và giảm thường xuyên thể hiện việc thu thập rác thường xuyên. Trong các bản ghi Dòng thời gian, biểu đồ số nút hoặc vùng nhớ khối xếp JS tăng và giảm thường xuyên cho biết việc thu thập rác thường xuyên.

Sau khi xác định được sự cố, bạn có thể sử dụng bản ghi Phân bổ dòng thời gian để tìm hiểu vị trí phân bổ bộ nhớ và chức năng nào đang gây ra việc phân bổ.