Quản lý bộ nhớ hiệu quả trong trò chơi

Trên nền tảng Android, hệ thống cố gắng sử dụng nhiều bộ nhớ hệ thống (RAM) nhất có thể và thực hiện nhiều hoạt động tối ưu hoá bộ nhớ để giải phóng dung lượng khi cần. Những hoạt động tối ưu hoá này có thể ảnh hưởng xấu đến trò chơi, làm trò chơi chạy chậm hoặc bị tắt hoàn toàn. Bạn có thể tìm hiểu thêm về những phương pháp tối ưu hoá này trong chủ đề Phân bổ bộ nhớ giữa các quy trình.

Trang này giải thích các bước bạn có thể thực hiện để tránh tình trạng dung lượng bộ nhớ thấp ảnh hưởng đến trò chơi của mình.

Phản hồi đến onTrimMemory()

Hệ thống sử dụng onTrimMemory() để thông báo cho ứng dụng của bạn rằng bộ nhớ sắp hết và ứng dụng có thể bị tắt. Nhiều lúc, đây là cảnh báo duy nhất mà ứng dụng nhận được. Lệnh gọi lại này có độ trễ cao so với low-memory killer, (LMK – mô đun tắt ứng dụng khi bộ nhớ thấp), do đó, quan trọng là bạn phải nhanh chóng phản hồi lệnh gọi lại.

Để phản hồi lệnh gọi lại này, bạn có thể giảm tốc độ, số lượng và quy mô phân bổ. onTrimMemory() truyền một hằng số cho biết mức độ nghiêm trọng, nhưng bạn nên phản hồi ngay từ cảnh báo đầu tiên vì có thể sự phân bổ xảy ra nhanh hơn khả năng phản ứng của onTrimMemory().

Kotlin

class MainActivity : AppCompatActivity(), ComponentCallbacks2 {
    override fun onTrimMemory(level: Int) {
        when (level) {
            ComponentCallbacks2.TRIM_MEMORY_MODERATE,
                ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
                ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> // Respond to low memory condition
            else -> Unit
        }
    }
}

Java

public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
    public void onTrimMemory(int level) {
        switch (level) {
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
              // Respond to low memory condition
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
              // Respond to low memory condition
                break;
            case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
              // Respond to low memory condition
                break;
            default:
                break;

C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

class LowMemoryTrigger : MonoBehaviour
{
    private void Start()
    {
        Application.lowMemory += OnLowMemory;
    }
    private void OnLowMemory()
    {
        // Respond to low memory condition (e.g., Resources.UnloadUnusedAssets())
    }
}

Sử dụng bản thử nghiệm API thông báo bộ nhớ

API thông báo bộ nhớ được phát triển làm một phương thức thay thế cho onOnMemory, có khả năng truy lại và độ chính xác cao hơn nhiều khi dự đoán các LMK đang chờ xử lý. Để làm được như vậy, API này ước tính lượng tài nguyên bộ nhớ đang sử dụng và thông báo cho ứng dụng khi vượt quá các ngưỡng nhất định. API cũng có thể báo cáo tỷ lệ phần trăm bộ nhớ ước tính đã sử dụng trực tiếp cho ứng dụng của bạn. Bạn có thể sử dụng API thông báo bộ nhớ làm phương thức thay thế cho các sự kiện onTrimMemory để quản lý bộ nhớ.

Để dùng API thông báo bộ nhớ, hãy xem hướng dẫn bắt đầu sử dụng.

Hãy sử dụng bộ nhớ tiết kiệm

Phân bổ bộ nhớ một cách thận trọng để tránh hết bộ nhớ. Sau đây là một số yếu tố cần xem xét:

  • Dung lượng RAM vật lý: Trò chơi thường sử dụng từ 1⁄4 đến 1⁄2 dung lượng RAM thực trên thiết bị.
  • Kích thước zRAM tối đa: Nhiều zRAM hơn có nghĩa là trò chơi có nhiều bộ nhớ để phân bổ hơn. Dung lượng này có thể khác nhau tuỳ theo thiết bị; hãy tìm SwapTotal trong /proc/meminfo để thấy giá trị này.
  • Mức sử dụng bộ nhớ của hệ điều hành: Các thiết bị chỉ định nhiều RAM cho quy trình của hệ thống thường chừa lại ít bộ nhớ cho trò chơi. Hệ thống sẽ tắt quy trình của trò chơi để bảo vệ các quy trình của hệ thống.
  • Mức sử dụng bộ nhớ của các ứng dụng đã cài đặt: Thử nghiệm trò chơi của bạn trên các thiết bị đã cài đặt nhiều ứng dụng. Các ứng dụng nhắn tin và mạng xã hội cần chạy liên tục và sẽ ảnh hưởng đến mức bộ nhớ còn trống.

Nếu bạn không thể đảm bảo việc sử dụng bộ nhớ tiết kiệm, hãy sử dụng một phương pháp linh hoạt hơn. Nếu hệ thống gặp sự cố sắp hết bộ nhớ, hãy giảm mức bộ nhớ mà trò chơi đang sử dụng. Ví dụ: phân bổ các kết cấu (texture) có độ phân giải thấp hơn hoặc giảm hiệu ứng đổ bóng để phản hồi onTrimMemory(). Phương pháp phân bổ bộ nhớ linh hoạt này yêu cầu nhà phát triển phải làm việc nhiều hơn, đặc biệt là trong giai đoạn thiết kế trò chơi.

Tránh tình trạng đơ máy

Tình trạng đơ máy xảy ra khi bộ nhớ còn trống thấp nhưng không đủ thấp để tắt trò chơi. Trong trường hợp này, kswapd đã lấy lại những trang mà trò chơi vẫn cần, do đó, kswapd vẫn sẽ thử tải lại các trang đó trong bộ nhớ. Do không có đủ dung lượng, các trang đó tiếp tục bị hoán đổi (hoán đổi liên tục). Công cụ Theo dõi hệ thống báo cáo tình trạng này dưới dạng một luồng trong đó kswapd chạy liên tục.

Một dấu hiệu của tình trạng đơ máy là thời gian kết xuất khung hình lâu – có thể là một giây hoặc lâu hơn. Giảm mức sử dụng bộ nhớ của trò chơi để giải quyết tình trạng này.

Sử dụng các công cụ có sẵn

Android có một bộ công cụ hỗ trợ việc hiểu cách hệ thống quản lý bộ nhớ.

Meminfo

Công cụ này thu thập số liệu thống kê về bộ nhớ để cho biết mức bộ nhớ PSS đã được phân bổ và các danh mục được sử dụng bộ nhớ đó.

In số liệu thống kê meminfo theo một trong các cách sau:

  • Sử dụng lệnh adb shell dumpsys meminfo package-name.
  • Sử dụng lệnh gọi MemoryInfo qua Android Debug API.

Số liệu thống kê PrivateDirty cho thấy dung lượng RAM trong tiến trình không thể phân trang vào ổ đĩa và không được chia sẻ với quy trình nào khác. Phần lớn dung lượng này sẽ được cung cấp cho hệ thống khi quy trình đó bị tắt.

Các điểm theo dõi bộ nhớ

Các điểm theo dõi bộ nhớ sẽ theo dõi lượng bộ nhớ RSS mà trò chơi đang sử dụng. Việc tính toán mức sử dụng bộ nhớ RSS nhanh hơn nhiều so với tính mức sử dụng PSS. Vì tốc độ tính nhanh hơn nên RSS cho thấy rõ hơn về những thay đổi trong kích thước bộ nhớ để đo lường chính xác hơn mức sử dụng bộ nhớ cao nhất. Do đó, bạn sẽ dễ dàng nhận thấy các lúc cao điểm có thể khiến trò chơi hết bộ nhớ.

Perfetto và các dấu vết dài

Perfetto là một bộ công cụ giúp thu thập thông tin về hiệu suất và bộ nhớ trên thiết bị và hiển thị trong giao diện người dùng dựa trên nền tảng web. Công cụ này hỗ trợ các dấu vết (trace) dài tuỳ ý để bạn có thể xem cách RSS thay đổi theo thời gian. Bạn cũng có thể đưa ra các truy vấn SQL trên dữ liệu mà công cụ này tạo ra để xử lý ngoại tuyến. Bật các dấu vết dài qua ứng dụng Theo dõi hệ thống. Hãy đảm bảo rằng bạn đã bật danh mục memory:Memory để theo dõi dấu vết.

heapprofd

heapprofd là một công cụ theo dõi bộ nhớ thuộc Perfetto. Công cụ này có thể giúp bạn tìm rò rỉ bộ nhớ bằng cách cho biết nơi bộ nhớ được phân bổ bằng malloc. Bạn có thể bắt đầu heapprofd bằng cách sử dụng tập lệnh Python. Vì công cụ này có mức hao tổn thấp nên sẽ không ảnh hưởng đến hiệu năng như các công cụ khác (ví dụ: Malloc Debug).

bugreport

bugreport là một công cụ ghi nhật ký để tìm hiểu xem trò chơi có gặp sự cố do hết bộ nhớ hay không. Kết quả mà công cụ xuất ra chi tiết hơn nhiều so với sử dụng logcat. Công cụ này hữu ích cho việc gỡ lỗi bộ nhớ vì nó cho biết rõ rằng trò chơi có gặp sự cố do hết bộ nhớ hoặc bị LMK tắt hay không.

Để biết thêm thông tin, hãy xem bài viết Ghi lại và đọc báo cáo lỗi.