# 游戏性能优化
> **过早优化是万恶之源** —— 但过晚优化是项目杀手。优化不是最后一步,而是贯穿开发始终的纪律。
---
## 目录
1. [性能优化方法论](#性能优化方法论)
2. [CPU 优化](#cpu-优化)
3. [GPU 优化](#gpu-优化)
4. [内存管理](#内存管理)
5. [加载与流送](#加载与流送)
6. [包体优化](#包体优化)
7. [移动端特化](#移动端特化)
8. [ profiling 工具与流程](#profiling-工具与流程)
9. [平台特定优化](#平台特定优化)
---
## 性能优化方法论
### 优化流程
```
正确优化顺序:
1. 测量(Measure)
└── 确定瓶颈:CPU / GPU / 内存 / IO / 网络
└── 工具:Profiler、帧时间分析、内存快照
2. 分析(Analyze)
└── 找到热点函数、资源消耗大户
└── 问:为什么慢?必要吗?有更快的方式吗?
3. 优化(Optimize)
└── 针对瓶颈做最小必要改动
└── 一次只改一个变量,便于验证
4. 验证(Verify)
└── 确认性能提升
└── 确认没有引入 bug
5. 重复(Repeat)
└── 瓶颈会转移,持续迭代
```
### 性能预算(Performance Budget)
| 平台 | 目标帧率 | 帧时间预算 | CPU 预算 | GPU 预算 |
|------|----------|-----------|----------|----------|
| **PC 高端** | 144 FPS | 6.94ms | 3ms | 3.5ms |
| **PC 主流** | 60 FPS | 16.67ms | 7ms | 8ms |
| **主机** | 30/60 FPS | 33.33/16.67ms | 按平台 | 按平台 |
| **移动高端** | 60 FPS | 16.67ms | 5ms | 10ms |
| **移动主流** | 30 FPS | 33.33ms | 10ms | 20ms |
### 常见瓶颈分布
```
典型游戏性能分布:
渲染(Rendering) ████████████████████ 40-50%
├── Draw Call 提交
├── Shader 执行
└── 后处理
游戏逻辑(Game Logic) ██████████ 20-30%
├── AI 更新
├── 物理模拟
└── 动画
CPU 渲染准备 ██████ 10-15%
├── 视锥剔除
├── 遮挡剔除
└── 渲染排序
内存/加载 ████ 5-10%
├── 资源加载
└── GC/内存分配
其他 ██ 5-10%
```
---
## CPU 优化
### Update 循环优化
```
问题:N 个对象的 Update() 每帧调用
优化策略:
1. 分层更新频率
├── 玩家/相机:每帧(60Hz)
├── 附近敌人:每 2 帧(30Hz)
├── 远处 NPC:每 5 帧(12Hz)
└── 环境动画:每 10 帧(6Hz)
2. 对象池(Object Pooling)
├── 避免频繁的 Instantiate/Destroy
├── 预分配对象池,复用
└── 特别适用于:子弹、粒子、敌人
3. 事件驱动替代轮询
├── 轮询:每帧检查条件
└── 事件:只在变化时执行
```
### 物理优化
| 优化 | 方法 | 效果 |
|------|------|------|
| **简化碰撞体** | 用 Box/Sphere 替代 Mesh Collider | 10-100x 提升 |
| **Layer 过滤** | 只计算必要的碰撞对 | 减少无效检测 |
| **Sleep 机制** | 静止物体进入睡眠 | 零开销 |
| **固定步长** | FixedUpdate 独立于渲染 | 稳定性 + 可预测 |
| **减少刚体数量** | 动画替代物理的表现效果 | 大幅降低负载 |
| **异步物理** | 物理在独立线程 | 并行化 |
### AI 优化
```
AI 更新优化:
1. 距离 LOD
├── < 10m:完整 AI(行为树全评估)
├── 10-50m:简化 AI(仅基础行为)
└── > 50m:睡眠 / 仅位置同步
2. 时间片(Time Slicing)
├── 每帧只更新 1/N 的 AI
├── 分散在多个帧执行
└── 玩家感知不到延迟
3. 空间分区
├── 四叉树/八叉树/Octree
├── 减少邻居查询从 O(n) 到 O(log n)
└── 适用于:群体 AI、寻路
```
### 算法优化
| 问题 | 低效方案 | 高效方案 | 提升 |
|------|----------|----------|------|
| 查找对象 | 遍历列表 | 字典/HashMap | O(n) → O(1) |
| 排序 | 每帧排序 | 增量排序/事件触发 | 10-100x |
| 字符串拼接 | + 操作 | StringBuilder | 避免 GC |
| LINQ 查询 | 链式 LINQ | 手动循环 | 3-10x |
| 反射调用 | Reflection | 委托/表达式树 | 10-100x |
---
## GPU 优化
### Draw Call 优化
```
Draw Call 成本:
- 每个 DC 有固定 CPU 开销(准备渲染状态)
- 目标:移动端 < 100,PC < 1000
优化方法:
1. 静态批处理(Static Batching)
└── 条件:静态物体、相同材质
└── 效果:合并网格,减少 DC
2. 动态批处理(Dynamic Batching)
└── 条件:小网格、相同材质
└── 自动进行,CPU 开销换 DC 减少
3. GPU Instancing
└── 条件:大量相同网格(草、树、粒子)
└── 效果:1 个 DC 渲染数千实例
4. SRP Batcher / GPU Resident Drawer
└── 新一代合批技术
└── 减少材质状态切换开销
```
### 着色器优化
| 优化 | 方法 | 收益 |
|------|------|------|
| **简化 Shader** | 移除不必要特性 | 减少寄存器占用 |
| **变体剥离** | 去掉未使用的 #pragma multi_compile | 减少编译时间/内存 |
| **精度优化** | float → half/fixed(移动端) | 2x ALU 吞吐 |
| **避免分支** | 用 lerp/step 替代 if | GPU 并行效率 |
| **减少纹理采样** | 合并通道、降采样 | 带宽节省 |
| **顶点着色器减负** | 顶点动画移到 CPU/纹理 | 减少顶点处理 |
### 光照与阴影
```
光照优化层级:
1. 实时光照(最昂贵)
├── 限制数量:主光源 + 1-2 辅光源
├── 使用 Light Probe 替代动态光
└── 移动端:尽量烘焙
2. 阴影(昂贵但重要)
├── 只给重要物体投射阴影
├── 降低阴影分辨率
├── 使用 Cascade Shadow Map 优化分布
└── 距离远时禁用阴影
3. 全局光照(GI)
├── 预计算 GI(Lightmap、Light Probe)
├── 实时 GI 限制在小范围
└── SSAO 替代全场景 AO
```
### 后处理优化
| 效果 | 开销 | 优化方案 |
|------|------|----------|
| **Bloom** | 中 | 降采样、限制迭代次数 |
| **SSAO/SSGI** | 高 | 半分辨率计算、时间累积 |
| **TAA** | 中 | 与运动向量复用 |
| **SSR** | 高 | 步进优化、镜面-only |
| **景深** | 中 | Bokeh 用散景纹理替代计算 |
| **色调映射** | 低 | 保持,几乎无开销 |
---
## 内存管理
### 内存预算分配
| 平台 | 总内存 | 游戏逻辑 | 资源 | 系统预留 |
|------|--------|----------|------|----------|
| **PC (16GB)** | ~12GB 可用 | 500MB | 10GB | 1.5GB |
| **主机** | 按平台 | 300MB | 按平台 | 固定 |
| **移动 (4GB)** | ~2.5GB 可用 | 200MB | 2GB | 300MB |
| **移动 (2GB)** | ~1.2GB 可用 | 100MB | 1GB | 100MB |
### 纹理内存优化
```
纹理优化策略:
1. 格式选择
├── 不透明漫反射:DXT1/BC1(4bpp)
├── 透明纹理:DXT5/BC3(8bpp)
├── 法线贴图:BC5(8bpp,高质量)
├── 移动端:ASTC(4x4 到 12x12 可变)
└── UI:PVR/ETC2(移动端)
2. 尺寸控制
├── 最大尺寸限制(移动端 1K-2K)
├── 非2幂纹理的额外开销
└── Mipmap:降采样时内存增加 33%
3. 流送(Streaming)
├── 按需加载 Mipmap 层级
├── 远处物体用低分辨率
└── 近处物体加载高分辨率
```
### GC 优化(Unity/C#)
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| **分配热点** | 每帧 new 对象 | 对象池、预分配 |
| **闭包分配** | Lambda 捕获变量 | 缓存委托、避免闭包 |
| **装箱** | 值类型转引用 | 泛型、避免 object 参数 |
| **字符串** | 字符串拼接 | StringBuilder、缓存 |
| **LINQ** | 隐式分配 | 手动循环替代 |
| **数组返回** | `new T[0]` | 返回静态空数组 |
### 内存泄漏检测
```
常见泄漏源:
1. 事件未取消订阅
└── 对象销毁前移除所有事件监听
2. 静态引用
└── 静态字典/列表持有对象引用
3. 纹理/材质未释放
└── 调用 Destroy(),注意引用计数
4. 协程未停止
└── 对象销毁时停止所有协程
5. UI 对象池溢出
└── 限制池大小,及时回收
```
---
## 加载与流送
### 加载时间预算
| 阶段 | 玩家容忍度 | 目标时间 | 优化手段 |
|------|-----------|----------|----------|
| **首次启动** | 低 | < 30s | 精简首包、分步加载 |
| **关卡切换** | 中 | < 5s | 异步加载、预加载 |
| **存档加载** | 中 | < 3s | 增量序列化 |
| **资源弹窗** | 极低 | < 100ms | 对象池、预实例化 |
| **场景内流送** | 无感 | 无缝 | 后台加载、LOD |
### 异步加载策略
```
关卡加载流程:
Phase 1: 预加载(上一关进行中)
├── 加载下一关公共资源
├── 解析关卡元数据
└── 准备对象池
Phase 2: 过渡(Loading Screen)
├── 异步加载核心资源
├── 显示加载进度
└── 播放加载动画/提示
Phase 3: 激活
├── 同步实例化关键对象
├── 初始化游戏状态
└── 淡入场景
Phase 4: 后台流送
├── 玩家附近的区域优先
├── 远处区域低优先级
└── 卸载远离玩家的区域
```
### 资源流送(World Streaming)
| 技术 | 原理 | 适用 |
|------|------|------|
| **关卡流送** | 按区域加载/卸载子关卡 | 线性关卡 |
| **世界分区** | 网格化世界,按需加载格子 | 开放世界 |
| **LOD 流送** | 距离决定资源精度 | 所有 3D 游戏 |
| **纹理流送** | 按需加载 Mipmap 层级 | 大纹理场景 |
| **动画流送** | 按需加载动画剪辑 | 大量角色 |
---
## 包体优化
### 包体构成分析
```
典型手游包体分布:
资源文件 ████████████████████ 60-70%
├── 纹理 ██████████ 35-40%
├── 音频 ████ 10-15%
├── 模型/动画 ███ 8-12%
└── 视频/字体 ██ 5-8%
代码 ██████ 15-20%
引擎运行时 ████ 10-15%
配置文件/其他 ██ 5-10%
```
### 包体优化策略
| 策略 | 方法 | 典型收益 |
|------|------|----------|
| **纹理压缩** | ASTC 6x6 / ETC2 | 30-50% 减少 |
| **音频压缩** | Vorbis/MP3 替代 WAV | 80-90% 减少 |
| **模型压缩** | 降低面数、Draco | 50-70% 减少 |
| **代码剥离** | IL2CPP + 托管代码剥离 | 30-50% 减少 |
| **资源分包** | 首包 + DLC/资源下载 | 首包减少 50%+ |
| **重复资源去重** | AssetBundle 共享 | 10-20% 减少 |
### 资源分包策略
```
首包内容(必须):
├── 启动画面、Loading UI
├── 主菜单场景
├── 核心角色/怪物(前 5 关)
├── 通用特效、UI 资源
└── 核心代码
下载包(按需):
├── 后续关卡场景
├── 后续角色/皮肤
├── 高清资源包(可选)
├── 多语言资源
└── 活动/赛季内容
```
---
## 移动端特化
### 移动端限制
| 限制 | 影响 | 应对策略 |
|------|------|----------|
| **发热** | CPU/GPU 降频 | 动态降画质、帧率 |
| **电量** | 玩家体验下降 | 降低更新频率 |
| **内存低** | 闪退 | 严格预算、及时释放 |
| **存储小** | 安装率低 | 包体控制、资源分包 |
| **网络不稳** | 在线功能受限 | 离线优先、断线重连 |
| **输入限制** | 复杂操作困难 | 简化 UI、手势优化 |
### 动态画质调整
```
自适应画质系统:
监测指标(每 5 秒):
├── 平均帧时间
├── 帧时间方差(稳定性)
├── 设备温度(如有 API)
└── 电池状态
调整策略:
├── 帧时间 > 预算 20% → 降一级画质
├── 帧时间 < 预算 50% → 可升一级画质
├── 温度高 → 优先降 CPU 负载(AI、物理)
├── 电量低 → 锁定 30FPS,降低特效
└── 网络差 → 简化同步、预测增强
画质层级:
Level 5: 最高(阴影、后处理、高分辨)
Level 4: 高(减少后处理)
Level 3: 中(降分辨率、简化阴影)
Level 2: 低(关闭阴影、简化特效)
Level 1: 最低(最低分辨率、最少特效)
```
### 触控优化
| 优化 | 说明 |
|------|------|
| **触控响应** | 输入延迟 < 50ms,使用低延迟渲染路径 |
| **手势识别** | 避免误触,合理设置触控区域 |
| **虚拟摇杆** | 死区设置、跟随手指、边缘吸附 |
| **UI 适配** | 安全区适配(刘海屏、圆角) |
| **性能模式** | 发热时自动降低渲染分辨率 |
---
## profiling 工具与流程
### 工具选择
| 平台 | CPU Profiler | GPU Profiler | 内存分析 | 帧分析 |
|------|-------------|-------------|----------|--------|
| **Unity** | Unity Profiler | Frame Debugger | Memory Profiler | Profiler + RenderDoc |
| **Unreal** | Unreal Insights | GPU Visualizer | Memory Report | RenderDoc / PIX |
| **Godot** | Built-in Profiler | N/A | Monitor | N/A |
| **Android** | Android Studio | Snapdragon Profiler | Android Studio | RenderDoc |
| **iOS** | Xcode Instruments | Metal Frame Capture | Xcode Allocations | Xcode GPU Frame |
### Profiling 流程
```
1. 基线测量
└── 记录当前帧时间、内存、Draw Call
2. 场景分类测试
├── 空场景(引擎开销基线)
├── 重度场景(最坏情况)
├── 典型场景(平均水平)
└── 过渡场景(加载、流送)
3. 热点识别
├── CPU:哪个函数耗时最多?
├── GPU:哪个 Pass / Draw Call 最贵?
├── 内存:哪类资源占用最多?
└── IO:哪个加载最慢?
4. 优化验证
└── 修改后对比基线数据
└── 确保没有负优化
5. 回归测试
└── 自动化性能测试
└── 告警阈值设置
```
### 关键指标(KPI)
| 指标 | 良好 | 需关注 | 危险 |
|------|------|--------|------|
| **帧时间** | < 16.6ms | 16.6-20ms | > 20ms |
| **帧率稳定性** | 方差 < 2ms | 2-5ms | > 5ms |
| **Draw Call** | < 200 | 200-500 | > 500 |
| **SetPass Call** | < 100 | 100-200 | > 200 |
| **内存使用** | < 预算 70% | 70-90% | > 90% |
| **GC 频率** | > 10s 间隔 | 5-10s | < 5s |
| **加载时间** | < 3s | 3-10s | > 10s |
---
## 平台特定优化
### PC 优化
```
PC 特有优势:
- 可变分辨率渲染(Dynamic Resolution Scaling)
- 多线程充分利用(Job System / DOTS)
- GPU 驱动优化(DLSS/FSR/XeSS)
- 大内存允许更多缓存
PC 注意点:
- 配置差异大,需多档画质预设
- 后台程序竞争资源
- 窗口/全屏模式性能差异
```
### 主机优化
| 平台 | 特性 | 优化方向 |
|------|------|----------|
| **PS5** | 高速 SSD、硬件光追 | 流送优化、光追利用 |
| **Xbox Series** | 智能分发、Quick Resume | 分辨率自适应 |
| **Switch** | 移动 SoC、可拆卸 | 移动级优化、动态分辨率 |
### Web / 小游戏
```
Web 平台限制:
- 下载大小严格限制(通常 < 50MB)
- 单线程(WebGL 无多线程)
- 内存受限(浏览器限制)
- 加载速度关键
优化策略:
- AssetBundle 分片加载
- 压缩格式:Brotli / Gzip
- 减少 Shader 变体
- 简化物理和 AI
```
---
## 最佳实践清单
- [ ] **建立性能预算**:项目初期定义各平台目标
- [ ] **自动化性能测试**:CI 中集成帧时间检测
- [ ] **Profile 先行**:优化前必须先测量
- [ ] **分级适配**:设计多档画质自动切换
- [ ] **对象池 everywhere**:避免运行时分配
- [ ] **纹理格式正确**:按平台选最优压缩格式
- [ ] **剔除最大化**:视锥 + 遮挡 + 距离剔除
- [ ] **LOD 全资源**:模型、纹理、动画、AI 都要有 LOD
- [ ] **异步一切**:加载、保存、IO 全部异步
- [ ] **真机测试**:编辑器性能不代表真机性能
---
## 相关页面
- [渲染管线](rendering-pipeline.md) — GPU 渲染优化细节
- [物理系统](physics-systems.md) — 物理性能优化
- [动画状态机](animation-state-machines.md) — 动画性能
- [游戏测试方法论](game-testing-methodology.md) — 性能测试方法