内存优化对于在 Android 上提供稳定、高性能的游戏体验至关重要。本指南简要介绍了内存效率的重要性、Android 操作系统如何管理进程内存限制,以及 Google Play 管理中心内的新内存指标,这些指标可帮助您监控和提升游戏的技术质量。
内存优化的重要性
优化游戏的内存对于保持玩家留存率、扩大设备兼容性以及遵守平台质量标准至关重要:
- 冷启动预防(用户体验和留存率):当玩家暂时切换到其他应用(例如,回复通知或查看消息)时,操作系统会将游戏进程置于后台。如果游戏的后台内存占用过高,系统的低内存终止守护程序 (LMK) 会优先终止游戏进程,以便为前台任务回收 RAM。当用户下次恢复游戏时,游戏必须经历漫长的冷启动,而不是无缝且即时的热恢复,即从存储空间中完全重新加载大型图形资源、音频和游戏引擎二进制文件。将后台内存用量保持在较低水平可防止这些静默后台终止,从而保留用户状态并确保玩家可以立即恢复会话。如需详细了解系统 LMK 行为,请参阅 Android Vitals - 低内存终止守护程序指南。
- 生态系统和设备稳定性:内存用量效率低下和内存泄漏会降低整体系统运行状况。当系统内存不足时,系统会面临严重压力,导致帧速率下降、界面卡顿和音频故障。如果内存压力过大,系统的低内存终止守护进程 (LMK) 会强制终止后台进程,导致其他应用在玩家切换任务时出现冷启动缓慢和用户状态丢失的情况。
- 平台级终止:从 Android 17(API 级别 37)开始,系统会更主动地终止占用过多内存的进程。如果游戏的占用空间过大,操作系统可能会突然终止其进程,而不会生成标准堆栈轨迹。
- 设备兼容性:虽然旗舰设备配备 12 GB 至 16 GB 的 RAM,但全球大部分游戏玩家使用的设备 RAM 只有 4 GB 或 6 GB。合理的内存管理可确保游戏在所有硬件层级上都能正常运行并快速响应,而无需复杂的单独资源包。
了解 Android 中的内存
为了设计有效的内存预算策略,开发者必须了解 Android 平台如何管理物理内存,以及如何衡量游戏的活跃内存占用空间。
Android 内存核心概念
如需了解平台级内存管理的基础概念,请参阅官方内存管理概览文档。此资源涵盖四个架构领域:
- 内存概览:Android 使用分页和内存映射 (mmap) 来管理 RAM。它不支持磁盘上的传统交换文件,而是依靠页面压缩(使用 zRAM)和页面回收来释放物理内存。
- 进程间的内存分配:Android 会在整个系统中共享 RAM。它会为 Dalvik 或 ART 虚拟机执行分配特定堆,同时允许原生开发环境(例如 C++ 游戏引擎)从原生系统堆请求内存。
- 应用内存管理:Android 在多进程模型下运行,要求应用动态监控其生命周期状态,并主动释放不必要的资源(例如未缓存的图形和位图),以支持系统运行状况。
- 进程和线程概览:系统会根据进程当前在用户感知层面的可见性和重要性,将其分类到不同的层级,从而确定在内存不足的情况下,哪些进程会保持活跃状态,哪些进程会首先终止。
“总内存占用量”指标
平台级 Android 17 内存限制器会使用总内存占用量(而非总常驻内存大小 [RSS] 或虚拟内存大小)来评估进程消耗。
总内存占用 = 匿名 RSS (RssAnon) + 未压缩的交换空间 (VmSwap)
为防止游戏超出平台限制,您必须确切了解这些指标在系统级代表什么。如需详细了解这些指标、物理 RAM 分配以及如何处理文件支持的页面,请参阅监控内存用量指南中的了解 RSS 和交换指标。
内存限制
为了维持系统稳定性并确保应用不会消耗过多资源,Android 平台会管理正在运行的进程的内存限制。
Android 17 及更高版本中的内存限制器
Android 17(API 级别 37)及更高版本使用 Linux cgroup v2 管理严格的单应用内存限制,以防止单个应用导致系统级不稳定。如需详细了解技术实现,请参阅 AOSP 内存限制器指南和优先考虑内存效率:Android 17 博客的基本步骤。
- 机制:内存限制器会监控所有应用进程,并根据进程的生命周期状态动态分配限制:
- 可见进程(前台):当前显示界面的应用进程预计会运行更大的资源工作集,因此会获得更宽松的限制。
- 不可见进程(后台或服务):在不显示界面的情况下执行活跃工作的应用进程会受到更严格、更具限制性的预算约束。
- 内核属性:该服务依赖于两个主要属性:
memory.high:软限制。如果超出此限制,内核会限制进程并尝试主动回收内存。这种回收可能会导致游戏性能下降。memory.swap.max:管理进程可以使用的交换空间或 zRAM 空间的硬上限。
- 终止行为:如果进程在超过
memory.high后继续分配匿名内存并耗尽其交换容量,则分配会失败,并且操作系统会静默终止该进程。系统会使用ApplicationExitInfo在内存限制器退出原因下记录此终止(从 Android 17、26Q4 开始提供)。
Play 管理中心 Vitals 中的新内存限制
为了帮助开发者主动识别内存问题,Google Play 在 Play 管理中心的 Android Vitals 中引入了新指标。Play 管理中心会跟踪游戏会话的第 90 百分位 (P90) 匿名 RSS + 交换空间内存占用,以识别极端离群值。
警告和强制执行阈值会根据设备的物理 RAM 容量和进程状态进行缩放。这些限制分两个不同阶段实施。
如需了解详细指南和内存限制,请参阅 Android Vitals - 不良行为阈值是什么?
用户感知的服务
可感知服务是 Android 系统认为用户可以注意到的关键后台进程。此状态涵盖以下所有正在运行的进程:
- 前台服务 (FGS)
- 加急作业
- 用户发起的数据传输作业
- 系统绑定的服务或其他应用绑定的服务
由于可感知服务专为后台中的关键、长时间运行的任务而设计,因此它们极易发生累积生命周期泄漏。Android 平台内存限制会将此状态视为非前台状态,这意味着,如果您的游戏处于后台但继续运行可感知服务,则会受到 Play 帮助中心页面中显示的更严格的后台或服务内存限制。当游戏从前台切换到后台可感知服务状态时,必须主动修剪不必要的资源。
R8 要求
为了尽可能缩减字节码大小并减少基本 Java 进程开销,Google Play 管理中心会将代码优化作为其应用质量指南的一部分进行评估。如需详细了解适用于游戏的优化要求和限制,请参阅 Android Vitals 文档中的 DEX 代码优化。
如需在标准 Android 项目中配置 R8,请按照启用应用优化指南操作。如需启用高级缩减和优化设置,请参阅在完整模式下使用 R8。如需确定哪些规则会阻止 R8 混淆类或移除死代码,请使用 R8 配置分析器。
如果您使用游戏引擎进行构建,则默认 R8 行为会因引擎和版本而异:
- Unity:代码缩减功能默认处于停用状态,因此您必须在项目设置中启用该功能。如需详细了解版本支持和配置步骤,请参阅使用 R8 缩减和优化 Unity 代码。
- Unreal Engine:从 UE 4.25 开始,R8 在发布 build 中默认处于启用状态,因此您需要管理 JNI 桥和插件的保留规则。如需详细了解版本详情和 UPL 配置,请参阅使用 R8 缩减和优化虚幻引擎代码。
位图要求
在现代高保真游戏中,位图会占用大量内存用量。在 Android 8.0(API 级别 26)及更高版本中,Bitmap 像素数据直接存储在非托管的原生堆中,因此未经优化的图片加载可能会导致进程超出平台内存阈值。如需了解有关图片缩放和缓存的最佳实践,请参阅优化图片使用。
监控内存用量
为了有效优化游戏的内存,您必须先了解 Android 平台如何衡量其占用空间。Android 17 更新了内存指标,以跟踪匿名 RSS (RssAnon) 和未压缩交换空间 (VmSwap) 的总和,不包括文件支持的内存或 GPU 专用内存。本指南详细介绍了如何使用 Perfetto 和 meminfo 等系统级工具,实现 ProfilingManager 和 onTrimMemory 等诊断 API,以及在 Unity 和 Unreal Engine 中提取精确的内存分配。了解如何准确分析游戏性能,并避免与传统运行时内存轮询相关的性能卡顿。
如需了解详情,请参阅监控内存用量。
内存用量缩减策略
虽然游戏引擎简化了跨平台开发,但其默认内存处理方式可能会触发操作系统级内存限制。本页详细介绍了专为 Unity 和 Unreal Engine 量身定制的实用优化步骤。了解为什么依赖基于 Java 的 onTrimMemory 可能会导致 Unity 中出现死锁,以及如何改用原生生命周期回调。您还将了解关键的资源级优化,例如使用 ASTC 8x8 纹理压缩和配置资源卸载,以确保游戏在所有硬件层级上都能流畅运行。
如需了解详情,请参阅减少内存用量。