Graphics & Games 高级 25m
支持性能密集型应用和游戏
Support performance-intensive apps and games
2020年6月26日
一句话判断
如果你的游戏或专业应用需要榨干设备的每一滴性能,这场 Session 讲解了如何绕过系统的各种限制——从内存分配到后台执行。
这场 Session 讲了什么
这场 Session 面向开发高性能游戏和专业应用的开发者,讲解了 iOS 和 iPadOS 中如何最大化利用系统资源。普通的 App 受到系统各种限制的约束——后台执行时间有限、内存使用有上限、CPU 使用率过高会被降频。但性能密集型应用(如 3A 游戏、视频编辑器、DAW)需要突破这些限制。
演讲者首先介绍了 Metal Performance HUD 和性能指标的概念。理解你的应用当前的性能状态(帧率、帧时间、GPU 利用率)是优化的前提。Session 推荐了几个关键指标:帧时间一致性(避免帧时间波动)、GPU 利用率(目标是 90%+)、和内存带宽使用。
然后深入讲解了内存管理策略。对于大型游戏来说,内存是比 GPU 更常见的瓶颈。演讲者介绍了如何使用 MTLHeap 来减少 Metal 资源分配的开销、如何利用 Memoryless Render Target 节省带宽,以及如何在 iOS 上正确处理内存警告。
Session 的后半部分讨论了热管理(Thermal Management)。当设备持续高负载时,芯片会发热,系统会降频保护硬件。演讲者展示了如何使用 ProcessInfo.ThermalState 来检测热状态,并在设备发热时主动降低画质以维持帧率稳定。
值得深挖的点
- 可持续性能 vs 爆发性能:iPhone 的峰值性能非常强,但只能维持几分钟。之后的持续性能可能只有峰值的 60-70%。你的游戏需要为这两种状态都做好设计——开场动画可以用峰值性能跑满效果,但核心游戏循环必须在持续性能水平上流畅运行。
- 内存压力的层级处理:iOS 的内存警告分三个级别。轻微警告时释放缓存,严重警告时释放非必要资源,致命警告时立即保存用户数据准备被系统终止。很多游戏只处理了致命警告,导致频繁被系统杀掉。
代码片段
// 监控设备热状态
NotificationCenter.default.addObserver(
forName: ProcessInfo.thermalStateDidChangeNotification,
object: nil, queue: .main
) { _ in
self.handleThermalStateChange()
}
func handleThermalStateChange() {
let state = ProcessInfo.processInfo.thermalState
switch state {
case .nominal:
// 正常状态,使用最高画质
setGraphicsQuality(.ultra)
case .fair:
// 轻微发热,降低一点画质
setGraphicsQuality(.high)
case .serious:
// 明显发热,大幅降低画质
setGraphicsQuality(.low)
reduceParticleSystemCount()
case .critical:
// 严重发热,最低画质
setGraphicsQuality(.minimum)
disableAllEffects()
@unknown default:
break
}
}
// 使用 MTLHeap 优化内存分配
func createResourceHeap(device: MTLDevice) {
let heapDescriptor = MTLHeapDescriptor()
heapDescriptor.size = 256 * 1024 * 1024 // 256MB
heapDescriptor.storageMode = .private // GPU 专用内存
let heap = device.makeHeap(descriptor: heapDescriptor)!
// 从 Heap 中分配纹理和 buffer,避免碎片化
let textureDescriptor = MTLTextureDescriptor()
textureDescriptor.width = 2048
textureDescriptor.height = 2048
textureDescriptor.pixelFormat = .rgba8Unorm
textureDescriptor.storageMode = .private
let texture = heap.makeTexture(descriptor: textureDescriptor)
// 当不再需要时,资源会回到 heap 供复用
}
// 处理内存警告
NotificationCenter.default.addObserver(
forName: UIApplication.didReceiveMemoryWarningNotification,
object: nil, queue: .main
) { _ in
self.handleMemoryWarning()
}
func handleMemoryWarning() {
// 释放可重建的缓存
textureCache.removeAll()
audioBufferPool.drain()
// 强制 GC(如果使用 ARC,大部分已自动管理)
// 建议系统回收资源
autoreleasepool {
// 清理临时对象
}
}
最佳实践
- 在开发阶段持续监控帧时间曲线,确保没有间歇性的性能抖动
- 使用 MTLHeap 管理频繁分配释放的 GPU 资源,减少内存碎片
- 根据热状态动态调整画质,不要等到系统强制降频才响应
- 内存警告时优先释放可重建的资源(如纹理缓存),保留不可重建的数据(如玩家进度)
- 在不同设备型号上测试性能表现,为低配设备准备降级方案
还有什么值得关注
- Apple Silicon Mac 的热管理策略与 iOS 设备类似,这些优化对两个平台都适用
- 搭配 “Optimize Metal Performance for Apple silicon Macs” 一起看,可以获得 Apple GPU 上的具体优化建议
- “Harness Apple GPUs with Metal” 讲解了 GPU 架构层面的优化策略
WWDC 2020