一、代码层面的优化技巧
1. 减少内存分配
问题:频繁创建对象导致GC疯狂回收!
效果:优化后GC压力降低90%,内存占用像坐过山车一样稳定!
C# 使用 .NET 的自动内存管理机制,由 垃圾回收器(GC) 负责回收不再使用的对象所占用的内存。
.NET GC 将托管堆分为三代:
回收频率:Gen 0 > Gen 1 > Gen 2
Gen 2 回收(Full GC)代价最高,应尽量避免。
- Gen 0:新分配的对象,回收最频繁。
- Gen 1:从 Gen 0 存活下来的对象。
- Gen 2:长期存活的对象(如静态变量、缓存等)。
cs
// 传统方式(频繁分配)
public List<int> GetNumbers(int count) {
List<int> numbers = new List<int>();
for (int i = 0; i < count; i++) {
numbers.Add(i); // 每次Add都可能分配新内存
}
return numbers;
}
// 优化方式(对象池复用)
public class NumberPool {
private static readonly ArrayPool<int> _pool = ArrayPool<int>.Shared;
public int[] GetNumbers(int count) {
int[] buffer = _pool.Rent(count); // 从池中租用数组
for (int i = 0; i < count; i++) {
buffer[i] = i;
}
return buffer;
}
public void ReturnBuffer(int[] buffer) {
_pool.Return(buffer); // 归还数组到池
}
}
2. 减少装箱拆箱
效果:泛型集合在处理值类型时不需要装箱操作,性能提升30%+!
- 装箱会将值类型转为引用类型,触发堆分配。
- 使用泛型(如
List<int>而非ArrayList)可避免装箱。
cs
// 问题:装箱拆箱
int num = 10;
object obj = num; // 装箱
int newNum = (int)obj; // 拆箱
// 优化:使用泛型集合
List<int> intList = new List<int> { 1, 2, 3, 4, 5 };
// 代替 ArrayList
ArrayList arrayList = new ArrayList { 1, 2, 3, 4, 5 };
3. 算法优化:从O(n²)到O(n)
效果:1000个订单的处理时间从10秒降到0.1秒!
cs
// 问题代码:O(n²)的嵌套循环
public List<Order> FilterOrdersByCustomer(List<Order> orders, string customerId) {
List<Order> result = new List<Order>();
foreach (var order in orders) {
foreach (var customer in orders) {
if (customer.CustomerId == customerId) {
result.Add(order);
}
}
}
return result;
}
// 优化代码:O(n)的哈希表
public List<Order> FilterOrdersByCustomerOptimized(List<Order> orders, string customerId) {
List<Order> result = new List<Order>();
Dictionary<string, List<Order>> customerOrders = new Dictionary<string, List<Order>>();
foreach (var order in orders) {
if (!customerOrders.ContainsKey(order.CustomerId)) {
customerOrders[order.CustomerId] = new List<Order>();
}
customerOrders[order.CustomerId].Add(order);
}
if (customerOrders.TryGetValue(customerId, out List<Order> ordersForCustomer)) {
result = ordersForCustomer;
}
return result;
}
4.减少不必要的对象分配
- 避免在循环中创建对象(尤其是引用类型)。
- 使用 值类型(struct) 替代小对象(注意装箱问题)。
- 重用对象(对象池、缓存)。
cs
// 不推荐:每次调用都分配新数组
byte[] buffer = new byte[1024];
// 推荐:栈分配或复用缓冲区
Span<byte> buffer = stackalloc byte[1024]; // 仅限 unsafe 或 .NET Core+
二、系统架构层面的优化
1. 多线程优化
cs
int sum = 0;
object lockObj = new object();
Parallel.ForEach(numbers, (number) => {
lock (lockObj) {
sum += number;
}
});
注意:合理利用多线程可以充分发挥多核处理器的性能,但要注意线程同步问题,避免死锁和竞态条件。
2. 缓存策略:减少数据库访问
cs
private static MemoryCache _cache = new MemoryCache(new MemoryCacheOptions());
public User GetUser(int userId)
{
User user = _cache.Get<User>($"user_{userId}");
if (user == null)
{
user = GetUserFromDatabase(userId); // 从数据库获取用户信息
_cache.Set($"user_{userId}", user, TimeSpan.FromMinutes(30));
}
return user;
}
效果:减少80%的数据库查询,响应速度提升5倍!
三、高级优化技术
1. 使用Span避免堆内存分配
效果:零堆内存分配,GC压力降低90%!
cs
public class TensorProcessor {
// 使用Span<T>避免分配临时数组
public void Normalize(float[] data, int size) {
Span<float> span = data; // 直接映射到原始数组
for (int i = 0; i < size; i++) {
span[i] = (span[i] - 128f) / 255f; // 归一化操作
}
}
// 传统方式(频繁GC)
public void NormalizeLegacy(float[] data, int size) {
float[] normalized = new float[size]; // 分配新数组
for (int i = 0; i < size; i++) {
normalized[i] = (data[i] - 128f) / 255f;
}
}
}
2. 内存池MemoryPool的实战应用
cs
public class MemoryPoolExample {
private readonly MemoryPool<float> _pool = MemoryPool<float>.Shared;
public void ProcessBatch(int batchSize, int size) {
for (int i = 0; i < batchSize; i++) {
var memory = _pool.Rent(size); // 从池中租借内存
try {
var span = memory.Span; // 填充数据并处理...
} finally {
_pool.Return(memory); // 归还内存
}
}
}
}
四、性能调优的方法论
性能调优不是"单点突破",而是"全链路优化",可分为四个层面:
- 代码层面:算法、数据结构、内存管理
- 框架层面:选择合适的框架和库
- 系统层面:操作系统、网络、数据库
- 硬件层面:CPU、内存、磁盘、网络
五、其他
1.用工具"诊断"性能瓶颈
就像医生用听诊器听心跳,我们也要用工具来"听"代码的心跳声:
- Visual Studio自带的诊断工具:可以分析CPU、内存和UI流畅性
- BenchmarkDotNet:专业性能基准测试工具
- dotnet-trace:收集运行中的性能数据
- 大多数现代服务应用应使用 Server GC。
- 不要手动调用
GC.Collect(),除非有明确性能数据支持。 - 使用 PerfView 或 dotMemory 分析 GC 停顿时间和分配热点。
- 结合 对象池(ArrayPool, MemoryPool) 和 Span/Memory 减少分配。
2.优化建议
| 优化方向 | 建议 |
| 内存分配 | 减少 new,复用对象,使用池化 |
| GC 压力 | 避免 LOH,减少 Gen 2 对象 |
| 资源管理 | 正确使用 IDisposable |
| 类型选择 | 合理使用 struct,避免装箱 |
| 工具辅助 | 使用 PerfView 分析 GC 行为 |
|---|
| 应用类型 | 推荐 GC 模式 | 理由 |
|---|---|---|
| 桌面 GUI 应用(WPF/WinForms) | Workstation GC(默认) | 用户交互敏感,需低延迟,避免 UI 卡顿 |
| ASP.NET Core Web API / 微服务 | Server GC | 高并发、多请求,需要高吞吐和快速回收 |
| 游戏(Unity / .NET) | Workstation + 手动优化 | 需要帧率稳定,避免 GC 停顿;常配合对象池 |
| 后台批处理 / 数据处理服务 | Server GC | 利用多核并行回收,提升处理效率 |
| 低内存设备(IoT、嵌入式) | Workstation GC | 内存受限,Server GC 内存开销大 |