# 游戏性能优化 Confidence: high Last verified: 2026-04-28 Generation: human_only # 游戏性能优化 > **过早优化是万恶之源** —— 但过晚优化是项目杀手。优化不是最后一步,而是贯穿开发始终的纪律。 --- ## 目录 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) — 性能测试方法