概述
前两篇专注于渲染和内存两个硬件的优化。这一篇回到 代码本身——同样的逻辑,不同的编码方式性能差距可达 10 倍以上。
代码性能优化的核心原则:选择正确的数据结构和算法,然后用编译器友好的方式编写。
1. 数据结构选择
1.1 List vs Array vs HashSet vs Dictionary
| 操作 |
List |
Array |
HashSet |
Dictionary |
| 顺序遍历(10K 元素) |
0.02ms |
0.02ms |
0.10ms |
0.10ms |
| 查找(1K 次) |
15ms(O(n)) |
15ms |
0.02ms(O(1)) |
0.02ms(O(1)) |
| 内存 |
低 |
最低 |
中 |
高 |
选择建议:
1 2 3 4 5 6 7 8
| var items = new[] { 1, 2, 3 };
var activePlayers = new HashSet<Player>();
var playerScores = new Dictionary<string, int>();
|
1.2 使用 NativeContainer 和 Burst
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| using Unity.Collections; using Unity.Jobs; using Unity.Burst;
[BurstCompile] public struct UpdateBulletJob : IJobParallelFor { public NativeArray<Vector3> positions; public NativeArray<Vector3> velocities; public float deltaTime;
public void Execute(int index) { positions[index] += velocities[index] * deltaTime; } }
|
2. 字符串优化
1 2 3 4 5 6 7 8 9 10 11 12 13
| string log = ""; for (int i = 0; i < 1000; i++) log += i + ", ";
var sb = new StringBuilder(); for (int i = 0; i < 1000; i++) sb.Append(i).Append(", ");
ReadOnlySpan<char> span = "Hello, World!"; var sub = span[7..12];
|
3. 循环优化
3.1 缓存友好遍历
1 2 3 4 5 6 7
| for (int i = 0; i < count; i++) { }
|
3.2 减少循环内部分支
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| for (int i = 0; i < enemies.Count; i++) { if (enemies[i].isActive) enemies[i].UpdateAI(); }
var active = new List<Enemy>(); for (int i = 0; i < enemies.Count; i++) if (enemies[i].isActive) active.Add(enemies[i]);
for (int i = 0; i < active.Count; i++) active[i].UpdateAI();
|
4. GetComponent 与反射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void Update() { var rigidbody = GetComponent<Rigidbody>(); rigidbody.AddForce(Vector3.up); }
private Rigidbody _rigidbody;
void Awake() { _rigidbody = GetComponent<Rigidbody>(); }
void Update() { _rigidbody.AddForce(Vector3.up); }
|
5. 性能对照表
| 操作 |
相对速度 |
| int x = 0 |
~0.3 ns |
| obj.Method() |
~3 ns |
| interface.Method() |
~8 ns |
| delegate.Invoke() |
~15 ns |
| GetComponent() |
~200 ns |
| FindObjectOfType() |
~2 us |
| Instantiate() |
~500 us |
总结
- 数据结构选型 是性能的基石
- 字符串是性能杀手,StringBuilder 和 ReadOnlySpan 是主要工具
- 循环优化 合并分支、缓存友好
- 缓存一切 GetComponent 结果
- 只在 Profiler 确认的瓶颈处优化,不要提前优化
下一篇将切入 ECS 实体组件系统,进入 Unity 数据驱动架构的实战领域。