Việc ghi lại quá trình phân bổ cho Java/Kotlin giúp bạn xác định những mẫu bộ nhớ không mong muốn có thể gây ra vấn đề về hiệu suất. Trình phân tích tài nguyên có thể cho bạn thấy những thông tin sau về tình trạng phân bổ đối tượng:
- Loại đối tượng được phân bổ và mức sử dụng của những đối tượng đó.
- Dấu vết ngăn xếp của mỗi mức phân bổ, bao gồm cả luồng chứa tương ứng.
- Thời điểm các đối tượng được giải phóng.
Bạn nên ghi lại quá trình phân bổ bộ nhớ trong khi người dùng tương tác theo cách bình thường và theo cách cực đoan để xác định chính xác nơi mã của bạn đang phân bổ quá nhiều đối tượng trong một thời gian ngắn hoặc phân bổ các đối tượng đã bị rò rỉ. Tìm hiểu thêm về lý do bạn nên phân tích bộ nhớ ứng dụng.
Cách ghi lại mức phân bổ cho Java/Kotlin
Để ghi lại mức phân bổ cho Java/Kotlin, hãy chọn tác vụ Track Memory Consumption (Java/Kotlin Allocations) (Theo dõi mức tiêu thụ bộ nhớ (Mức phân bổ cho Java/Kotlin)) trong thẻ Home (Trang chủ) của trình phân tích tài nguyên. Xin lưu ý rằng bạn cần một ứng dụng có thể gỡ lỗi (sử dụng Trình phân tích tài nguyên: chạy "ứng dụng" ở chế độ có thể gỡ lỗi (dữ liệu đầy đủ)) để ghi lại các hoạt động phân bổ Java/Kotlin.
Theo mặc định, Android Studio ghi lại mọi lượt phân bổ đối tượng trong bộ nhớ. Nếu có một ứng dụng phân bổ rất nhiều đối tượng, có thể bạn sẽ quan sát thấy tình trạng ứng dụng bị chậm lại trong quá trình phân tích. Để cải thiện hiệu suất trong khi phân tích, hãy chuyển đến trình đơn thả xuống Allocation Tracking (Theo dõi việc phân bổ) rồi chọn Sampled (Lấy mẫu) thay vì Full (Đầy đủ). Khi lấy mẫu, trình phân tích tài nguyên sẽ thu thập các lượt phân bổ đối tượng trong bộ nhớ theo chu kỳ.
Để buộc thực hiện một sự kiện thu gom rác trong khi ghi lại, hãy nhấp vào biểu tượng thùng rác .
Tổng quan về hoạt động phân bổ Java/Kotlin
Sau khi dừng ghi, bạn sẽ thấy những thông tin sau:
- Tiến trình sự kiện cho thấy trạng thái hoạt động, sự kiện nhập của người dùng và sự kiện xoay màn hình.
- Tiến trình sử dụng bộ nhớ cho thấy thông tin sau. Chọn một phần của tiến trình để lọc theo một phạm vi thời gian nhất định.
- Một biểu đồ xếp chồng về lượng bộ nhớ mà mỗi danh mục bộ nhớ đang sử dụng, biểu thị bằng trục y ở bên trái và khoá màu ở trên cùng.
- Một đường đứt nét thể hiện số lượng đối tượng được phân bổ, biểu thị theo trục y ở bên phải.
- Một biểu tượng cho mỗi sự kiện thu gom rác.
- Thẻ Bảng cho thấy danh sách các lớp học. Tổng số là số lượng phân bổ vào cuối phạm vi thời gian đã chọn (Phân bổ trừ đi Giải phóng), vì vậy, bạn nên gỡ lỗi các lớp có giá trị Tổng số cao nhất trước. Nếu bạn quan tâm hơn đến việc khắc phục sự cố cho các lớp học dựa trên mức phân bổ cao nhất trong phạm vi thời gian đã chọn, hãy ưu tiên theo Mức phân bổ. Tương tự, Remaining Size (Kích thước còn lại) là Allocations Size (Kích thước phân bổ) trừ đi Deallocations Size (Kích thước giải phóng) tính bằng byte.
- Khi bạn nhấp vào một lớp trong danh sách Bảng, ngăn Phiên bản sẽ mở ra cùng với danh sách các đối tượng được liên kết, bao gồm cả thời điểm chúng được phân bổ, thời điểm chúng được huỷ phân bổ và kích thước nông của chúng.
Thẻ Hình ảnh cho thấy chế độ xem tổng hợp của tất cả các đối tượng trong ngăn xếp lệnh gọi trong phạm vi thời gian đã chọn. Về cơ bản, thông tin này cho biết tổng dung lượng bộ nhớ mà ngăn xếp lệnh gọi có các thực thể được hiển thị chiếm. Hàng đầu tiên cho biết tên của chuỗi. Theo mặc định, các đối tượng được xếp chồng từ trái sang phải dựa trên kích thước phân bổ; hãy dùng trình đơn thả xuống để thay đổi thứ tự.
Sử dụng trình đơn thả xuống heap để lọc theo một số heap nhất định. Ngoài các bộ lọc có sẵn khi bạn ghi lại một tệp báo lỗi, bạn có thể lọc theo các lớp trong vùng nhớ khối xếp JNI, vùng nhớ khối xếp cho biết nơi phân bổ và giải phóng các lượt tham chiếu Giao diện gốc Java (JNI).
Sử dụng trình đơn thả xuống sắp xếp để chọn cách sắp xếp các lượt phân bổ. Ngoài các cách sắp xếp có sẵn khi chụp kết xuất heap, bạn có thể sắp xếp theo ngăn xếp lệnh gọi.
Cách tính bộ nhớ
Các con số bạn thấy ở đầu được dựa trên tất cả các trang bộ nhớ riêng tư mà ứng dụng của bạn đã cam kết, theo hệ thống Android. Số liệu này không bao gồm các trang được chia sẻ với hệ thống hoặc các ứng dụng khác. Có các danh mục sau trong phần mức sử dụng bộ nhớ:
- Java: Mức sử dụng bộ nhớ của các đối tượng được phân bổ qua mã Java hoặc Kotlin.
Native (Mã gốc): Mức sử dụng bộ nhớ của các đối tượng được phân bổ qua mã C hoặc C++.
Ngay cả khi không dùng C++ trong ứng dụng, ở đây bạn vẫn có thể thấy bộ nhớ mà mã gốc dùng (native memory) do khung Android sử dụng loại bộ nhớ này để thay mặt bạn xử lý nhiều thao tác, chẳng hạn như khi xử lý thành phần hình ảnh hoặc các thành phần đồ hoạ khác (mặc dù bạn viết mã bằng Java hoặc Kotlin).
Graphics (Đồ hoạ): Bộ nhớ dùng cho các hàng đợi bộ đệm đồ hoạ để hiển thị các pixel lên màn hình, bao gồm cả bề mặt GL, kết cấu GL, v.v. Xin lưu ý rằng đây là bộ nhớ dùng chung với CPU, không phải bộ nhớ GPU chuyên dụng.
Stack (Ngăn xếp): Bộ nhớ mà cả ngăn xếp gốc và ngăn xếp Java trong ứng dụng của bạn sử dụng. Số liệu này thường liên quan đến số lượng luồng mà ứng dụng của bạn đang chạy.
Mã: Bộ nhớ mà ứng dụng của bạn dùng cho mã và tài nguyên, chẳng hạn như mã byte DEX, mã DEX được tối ưu hoá hoặc biên dịch, .
so
và phông chữ.Khác: Bộ nhớ mà ứng dụng của bạn sử dụng nhưng hệ thống không chắc chắn về cách phân loại.
Allocated (Đã phân bổ): Số lượng đối tượng Java/Kotlin mà ứng dụng của bạn đã phân bổ. Số liệu này không tính các đối tượng được phân bổ trong C hoặc C++.
Kiểm tra bản ghi phân bổ
Để kiểm tra bản ghi mức phân bổ, hãy làm theo các bước sau:
- Duyệt xem danh sách lớp trong thẻ Bảng để tìm những đối tượng có giá trị Phân bổ hoặc Tổng số lớn bất thường (tuỳ thuộc vào mục tiêu tối ưu hoá của bạn) và có thể bị rò rỉ.
- Trong ngăn Instance View (Chế độ xem thực thể), hãy nhấp vào một thực thể. Tuỳ thuộc vào những gì áp dụng cho phiên bản đó, thẻ Trường hoặc Ngăn xếp lệnh gọi phân bổ sẽ mở ra. Sử dụng thông tin trong thẻ Trường hoặc Ngăn xếp lệnh gọi phân bổ để xác định xem các phiên bản có thực sự cần thiết hay là các bản sao không cần thiết.
Nhấp chuột phải vào mục bất kỳ trong danh sách để chuyển đến mã nguồn có liên quan.
Xem các lượt tham chiếu đến JNI toàn cục
Giao diện gốc Java (JNI) là một khung cho phép mã Java và mã gốc gọi lẫn nhau. Các lượt tham chiếu JNI được mã gốc quản lý theo cách thủ công. Vì vậy, có thể xảy ra các vấn đề, bao gồm cả những vấn đề sau:
- Các đối tượng Java do mã gốc sử dụng được duy trì hoạt động trong thời gian dài.
- Có thể không truy cập được một số đối tượng trên vùng nhớ khối xếp Java nếu lượt tham chiếu JNI bị loại bỏ nhưng trước đó chưa thể hiện rõ thao tác xoá.
- Đã sử dụng hết hạn mức tham chiếu JNI toàn cục.
Để khắc phục các vấn đề như vậy, hãy chọn Xem vùng nhớ khối xếp JNI trong trình phân tích tài nguyên để duyệt xem tất cả các lượt tham chiếu JNI cục bộ rồi lọc chúng theo loại Java và ngăn xếp lệnh gọi gốc. Nhấp chuột phải vào một trường thực thể trong thẻ Fields (Trường) rồi chọn Go to instance (Chuyển đến thực thể) để xem ngăn xếp lệnh gọi phân bổ có liên quan.
Thẻ Allocation Call Stack (Ngăn xếp lệnh gọi phân bổ) cho biết nơi các lượt tham chiếu JNI được phân bổ và giải phóng trong mã của bạn.
Để biết thêm thông tin về JNI, hãy xem nội dung các mẹo về JNI.