在游戏中有效地管理内存

在 Android 平台上,系统尝试使用尽可能多的系统内存 (RAM),并在需要时执行各种内存优化以释放空间。这些优化可能会对您的游戏产生负面影响,例如导致游戏速度变慢或完全崩溃。您可以在主题 进程间内存分配 中了解更多关于这些优化的信息。

本页面介绍了您可以采取的步骤,以避免低内存情况影响您的游戏。

响应 onTrimMemory()

系统使用 onTrimMemory() 通知您的应用内存不足,应用可能会被终止。许多情况下,这是您的应用收到的唯一警告。 相对于 低内存杀手 (LMK),此回调具有较高的延迟,因此快速响应回调至关重要。

响应此回调,减少分配的速度、数量和大小。 onTrimMemory() 传递一个常量来指示严重程度,但您应该响应第一个警告,因为可能分配速度比 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())
    }
}

使用内存建议 API beta

内存建议 API 是作为 onTrimMemory 的替代方案而开发的,它在预测即将到来的 LMK 方面具有更高的召回率和精度。该 API 通过估计正在使用的内存资源量来实现这一点,然后在超过特定阈值时通知应用。该 API 还可以将估计的内存使用率百分比直接报告给您的应用。您可以将内存建议 API 用作 onTrimMemory 事件的替代方案,用于内存管理。

要使用内存建议 API,请使用 入门指南。

保守使用内存预算

保守地预算内存,以避免内存不足。以下是一些需要考虑的因素:

  • 物理 RAM 大小:游戏通常使用设备物理 RAM 量的一半到四分之一。
  • 最大 zRAM 大小:zRAM 越多,游戏可分配的内存就越多。此数量根据设备而异;在 /proc/meminfo 中查找 SwapTotal 以找到此值。
  • 操作系统内存使用量:将更多 RAM 分配给系统进程的设备为您的游戏留下的内存更少。系统会在终止系统进程之前终止游戏的进程。
  • 已安装应用的内存使用量:在安装了许多应用的设备上测试您的游戏。社交媒体和聊天应用需要持续运行,并且会影响可用内存量。

如果您不能保证保守的内存预算,请采用更灵活的方法。如果系统遇到低内存问题,请减少游戏使用的内存量。例如,响应 onTrimMemory() 分配分辨率较低的纹理或存储较少的着色器。这种动态的内存分配方法需要开发人员付出更多努力,尤其是在游戏设计阶段。

避免抖动

抖动是指当可用内存很低但不足以终止游戏时发生的情况。在这种情况下,kswapd 已回收游戏仍需使用的页面,因此它会尝试从内存中重新加载这些页面。没有足够的空间,因此这些页面会不断被换出(连续换出)。系统跟踪 将此情况报告为一个线程,其中 kswapd 持续运行。

抖动的一个症状是帧时间过长,可能是一秒或更长。减少游戏的内存占用量以解决此问题。

使用可用工具

Android 提供了一组工具,可帮助您了解系统如何管理内存。

Meminfo

此工具收集内存统计信息,以显示分配了多少 PSS 内存 以及用于这些内存的类别。

以下列出打印 meminfo 统计信息的方法:

  • 使用命令 adb shell dumpsys meminfo package-name
  • 使用 Android 调试 API 中的 MemoryInfo 调用。

PrivateDirty 统计信息显示进程内无法分页到磁盘且未与任何其他进程共享的 RAM 量。当该进程被终止时,这部分内存的大部分将可供系统使用。

内存跟踪点

内存跟踪点跟踪游戏使用的 RSS 内存 量。计算 RSS 内存使用量比计算 PSS 使用量快得多。由于计算速度更快,RSS 显示内存大小变化的更精细粒度,从而更准确地测量峰值内存使用量。因此,更容易注意到可能导致游戏内存不足的峰值。

Perfetto 和长跟踪

Perfetto 是一套工具,用于收集设备上的性能和内存信息,并将其显示在基于 Web 的 UI 中。它支持任意长的跟踪,因此您可以查看 RSS 如何随时间变化。您还可以对它生成的数据发出 SQL 查询,以便离线处理。从 系统跟踪应用 中启用长跟踪。确保为跟踪启用了 **memory:Memory** 类别。

heapprofd

heapprofd 是 Perfetto 的一部分,是一种内存跟踪工具。此工具可以通过显示使用 malloc 分配内存的位置来帮助您查找内存泄漏。可以使用 Python 脚本启动 heapprofd,并且由于该工具的开销很低,因此不会像 Malloc Debug 等其他工具那样影响性能。

bugreport

bugreport 是一个日志记录工具,用于确定游戏是否因内存不足而崩溃。该工具的输出比使用 logcat 更详细。它对内存调试很有用,因为它会显示游戏是否因内存不足而崩溃,或者是被 LMK 终止的。

有关更多信息,请参阅 捕获和阅读错误报告