Trong hệ thống Android, ngưỡng giới hạn bộ nhớ cho Bộ giới hạn bộ nhớ (Android 17 trở lên) và giá trị điểm chuẩn cho chỉ số quan trọng về bộ nhớ trong Google Play Console là "RSS ẩn danh + bộ nhớ hoán đổi". Giá trị này thể hiện mức áp lực bộ nhớ thực tế mà quy trình chiếm giữ và là một chỉ số quan trọng mà bạn phải theo dõi để ứng dụng hoạt động ổn định.
Hiện tại, rất khó đo lường mức sử dụng bộ nhớ khớp chính xác với "RSS ẩn danh + trao đổi" tại thời gian chạy hoặc tĩnh trong Unity Engine.
Để giải quyết vấn đề này, trang này giới thiệu cách theo dõi giá trị "RSS ẩn danh + trao đổi" với độ tin cậy cao thông qua phương pháp ước tính bằng Unity Profiler, ProfileRecorder API và Unity Memory Profiler trong môi trường Unity Engine.
Kiểm tra mức sử dụng bộ nhớ trong thời gian chạy
Trong Unity, việc đo lường chính xác mức sử dụng bộ nhớ "RSS ẩn danh + bộ nhớ hoán đổi" của Android theo thời gian chạy mà không cần tốn nhiều tài nguyên có thể là một thách thức. Tuy nhiên, bạn có thể ước tính giá trị này một cách gần đúng (trong phạm vi sai số khoảng 10%) bằng cách sử dụng các API Trình phân tích tài nguyên tích hợp của Unity.
Cách 1: Sử dụng Profiler (Trình phân tích tài nguyên)
Bạn có thể ước tính tổng mức sử dụng bộ nhớ bằng cách cộng các giá trị do các API Trình phân tích tài nguyên sau đây trả về:
using UnityEngine;
using UnityEngine.Profiling;
public class MemoryMonitor : MonoBehaviour
{
public long GetEstimatedMemoryUsageBytes()
{
long totalReserved = Profiler.GetTotalReservedMemoryLong();
long monoHeapSize = Profiler.GetMonoHeapSizeLong();
return totalReserved + monoHeapSize;
}
}
Cách 2: Sử dụng lớp ProfilerRecorder
Bạn có thể theo dõi các chỉ số Tổng bộ nhớ được đặt trước và Bộ nhớ được đặt trước Gfx bằng ProfilerRecorder:
Trong bản dựng Phát triển: Tính toán "Tổng bộ nhớ dành riêng" – "Bộ nhớ dành riêng Gfx".
Trong bản phát hành: Sử dụng trực tiếp "Tổng bộ nhớ được dành riêng".
using Unity.Profiling;
using UnityEngine;
public class MemoryMonitor : MonoBehaviour
{
ProfilerRecorder totalRecorder;
#if DEVELOPMENT_BUILD
ProfilerRecorder gfxRecorder;
#endif
private void OnEnable()
{
totalRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
#if DEVELOPMENT_BUILD
gfxRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Gfx Reserved Memory");
#endif
}
private void OnDisable()
{
totalRecorder.Dispose();
#if DEVELOPMENT_BUILD
gfxRecorder.Dispose();
#endif
}
public long GetEstimatedMemoryUsageBytes()
{
#if DEVELOPMENT_BUILD
if (totalRecorder.Valid && gfxRecorder.Valid)
{
return totalRecorder.LastValue - gfxRecorder.LastValue;
}
#else
if (totalRecorder.Valid)
{
return totalRecorder.LastValue;
}
#endif
return 0;
}
}
Hạn chế:
Các API này không thể theo dõi những hoạt động phân bổ bộ nhớ bỏ qua Trình quản lý bộ nhớ của Unity (ví dụ: NativeMalloc(IntPtr size)).
Các API này có thể không được hỗ trợ tuỳ thuộc vào phiên bản Unity của bạn.
Phân tích mức sử dụng bộ nhớ (phân tích tĩnh)
Nếu phát hiện thấy mức sử dụng bộ nhớ cao trong thời gian chạy, bạn cần xác định vị trí bộ nhớ đang được sử dụng. Việc phân tích mức phân bổ bộ nhớ cho phép bạn loại bỏ các hoạt động phân bổ không cần thiết và giảm mức sử dụng bộ nhớ tổng thể của trò chơi.
Trình phân tích bộ nhớ Unity
Để thực hiện phân tích bộ nhớ chuyên sâu và tối ưu hóa trò chơi, hãy sử dụng gói Trình phân tích bộ nhớ Unity. Cách xác định vị trí các mục tương ứng với mức sử dụng "RSS ẩn danh + bộ nhớ hoán đổi" của hệ điều hành Android:
- Chụp ảnh chụp nhanh bằng Unity Trình phân tích bộ nhớ.
- Mở ảnh chụp nhanh và chuyển đến phần Tất cả bộ nhớ > Bộ nhớ thường trú trên thiết bị.
Tính tổng của các mục sau:
- Không được theo dõi
- Android Runtime
- Mã gốc
- Được quản lý
Hình 1. Nội dung mô tả bộ nhớ được lưu trữ trong bộ nhớ thường trú
Tổng số này đóng vai trò là một chỉ số thay thế thực tế cho "RSS ẩn danh + không gian hoán đổi" của hệ điều hành Android, cung cấp thông tin chi tiết hữu ích để phân tích bộ nhớ trò chơi.
Hạn chế:
Khi bộ nhớ chịu áp lực lớn, hệ điều hành Android có thể nén hoặc hoán đổi các trang bộ nhớ đang hoạt động để giải phóng RAM. Vì Trình phân tích bộ nhớ Unity không thể theo dõi bộ nhớ được hoán đổi, nên có thể xảy ra sự khác biệt trong các trường hợp mức sử dụng bộ nhớ cao.
Các tính năng này có thể bị hạn chế tuỳ thuộc vào phiên bản Unity bạn đang dùng.
Ví dụ về tập lệnh C#
Bạn có thể tham khảo các tập lệnh AndroidAndroidProcessStats.cs và GameMemoryMonitor.cs để xem ví dụ về cách theo dõi trạng thái và mức sử dụng bộ nhớ của các quy trình trong trò chơi của bạn trong thời gian chạy.
- Tập lệnh
AndroidProcessStatsminh hoạ cách sử dụng JNI (Giao diện gốc Java) để liên kết với các APIActivityManagercủa Android và cung cấp chức năng tìm nạp các quy trình đang chạy, tầm quan trọng của các quy trình đó và trạng thái ở cấp hệ điều hành. Nó cũng chứa các phương thức đơn giản để đọc số liệu thống kê về bộ nhớ trực tiếp từ hệ thống tệp/proccủa Linux. - Tập lệnh
GameMemoryMonitorcho biết cách kết nối thông tin này để theo dõi và gỡ lỗi liên tục, bao gồm cả cách thăm dò các API Android trên một luồng nền để ngăn chặn hiệu suất bị ảnh hưởng (vì việc sử dụng JNI và thăm dò thông tin bộ nhớ có thể tốn kém), cũng như cách kết nối với các sự kiện vòng đời nhưOnApplicationPauseđể theo dõi các thay đổi về bộ nhớ khi ứng dụng chạy ở chế độ nền hoặc tiếp tục hoạt động.
Để sử dụng các công cụ này, hãy thêm cả hai tập lệnh vào thư mục Assets (Tài sản) và đính kèm tập lệnh GameMemoryMonitor vào một GameObject trong cảnh của bạn.
Đánh giá chính xác hơn
Để xác minh chính xác các giá trị "RSS ẩn danh + bộ nhớ hoán đổi" của hệ điều hành Android, hãy sử dụng Perfetto. Công cụ này cho phép bạn đo lường chính xác mức sử dụng bộ nhớ ở cấp hệ thống và phân tích kỹ lưỡng mức sử dụng bộ nhớ của trò chơi.