Profile and optimize your game's memory
Graphics & Games 进阶 20m

分析和优化游戏内存

Profile and optimize your game's memory

2022年6月6日

在 Apple 官方观看视频

一句话判断

“内存分配不等于实际内存占用”——如果你的游戏因为内存问题被系统终止,这场 Session 会帮你搞清楚到底发生了什么以及如何诊断。

这场 Session 讲了什么

Apple GPU 软件团队的 Jack Xu 和 Seth Lu 系统讲解了游戏内存的分析和优化方法。内容从内存的基本概念开始,逐步深入到 Instruments 的内存分析工具、Xcode 的内存图分析、以及 Metal Debugger 的资源优化。

Session 的核心洞察是:分配(Allocations)和实际内存使用(Memory Footprint)是两个不同的概念。分配发生在虚拟地址空间,实际内存使用发生在物理内存。系统按物理内存页面(16KB)向你的游戏收费,不是按分配量收费。

今年新增了 Game Memory Instruments 模板,专门用于分析 Metal 游戏的内存增长。

值得深挖的点

分配 vs 实际内存。 游戏申请内存分配时,空间预留在了虚拟地址空间。只有当游戏实际访问这些内存时,系统才会在物理内存中准备空间。这意味着分配 100MB 不一定占用 100MB 物理内存。内存页分为三类:Dirty(已写入的内存)、Compressed(被压缩的不活跃页面)、Clean(只读映射文件,不计入 footprint)。

Memory Footprint 是核心指标。 Footprint = Dirty + Compressed + Swapped。这是系统用于执行内存限制的指标。在 Apple Silicon 上,CPU 和 GPU 共享统一内存,Metal 资源也计入 Dirty 内存。你的游戏可以通过 API 查询当前 footprint 和可用内存。

Game Memory 模板。 Instruments 今年新增的模板包含多个工具:Allocations 记录分配历史、Metal Resource Events 追踪 Metal 资源、VM Tracker 记录内存 footprint、Virtual Memory Trace 追踪虚拟内存活动。这个模板专为游戏内存分析设计。

内存页面的生命周期。 每个内存页面 16KB。不活跃的 Dirty 页面可能被系统压缩或换出到磁盘。当游戏再次访问这些页面时,系统会解压或从磁盘换入。你的游戏仍然按未压缩大小被收费。

代码片段

import os.proc

// 查询当前可用的系统内存(iOS/iPadOS/tvOS)
let availableMemory = os_proc_available_memory()
print("可用内存: \(availableMemory / 1024 / 1024) MB")

// 查询当前游戏的内存 footprint
import os.proc

var info = rusage_info_v6()
var infoCount = mach_msg_type_number_t(MemoryLayout<rusage_info_v6>.size / MemoryLayout<integer_t>.size)
let result = withUnsafeMutablePointer(to: &info) { infoPtr in
    infoPtr.withMemoryRebound(to: &infoCount, capacity: 1) { countPtr in
        proc_pid_rusage(getpid(), RUSAGE_INFO_V6, countPtr)
    }
}

if result == 0 {
    let footprint = info.ri_phys_footprint
    let lifetimeMax = info.ri_lifetime_max_phys_footprint
    print("当前 footprint: \(footprint / 1024 / 1024) MB")
    print("生命周期最大 footprint: \(lifetimeMax / 1024 / 1024) MB")
}

最佳实践

  • 关注 Memory Footprint 而非分配量——前者是系统限制和终止的依据
  • 使用 Xcode 的 Memory Report 作为第一步概览,用 Instruments 的 Game Memory 模板做深入分析
  • 从新启动开始分析(而非附加到已有进程),确保捕获完整的启动期内存增长
  • Apple Silicon 上 Metal 资源计入 Dirty 内存,优化纹理和缓冲区大小能直接减少 footprint
  • 使用 os_proc_available_memory() 在运行时动态调整资源使用策略
  • Clean 内存虽然不计入 footprint,但过多的文件映射会拖慢系统

还有什么值得关注

  • Metal Debugger 可以分析 Metal 资源(纹理、缓冲区、管线状态对象)的使用效率
  • Xcode 的内存图调试器可以分析对象引用关系,发现内存泄漏
  • 不同 Apple 平台有不同的内存限制,需要针对目标设备进行测试
  • 压缩内存仍然被收费,只是占用的物理内存更少——但它会增加 CPU 开销
WWDC 2022