【C#】性能优化

一、代码层面的优化技巧

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); // 归还内存
            }
        }
    }
}

四、性能调优的方法论

性能调优不是"单点突破",而是"全链路优化",可分为四个层面:

  1. 代码层面:算法、数据结构、内存管理
  2. 框架层面:选择合适的框架和库
  3. 系统层面:操作系统、网络、数据库
  4. 硬件层面:CPU、内存、磁盘、网络

五、其他

1.用工具"诊断"性能瓶颈

就像医生用听诊器听心跳,我们也要用工具来"听"代码的心跳声:

  • Visual Studio自带的诊断工具:可以分析CPU、内存和UI流畅性
  • BenchmarkDotNet:专业性能基准测试工具
  • dotnet-trace:收集运行中的性能数据
  • 大多数现代服务应用应使用 Server GC
  • 不要手动调用 GC.Collect(),除非有明确性能数据支持。
  • 使用 PerfViewdotMemory 分析 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 内存开销大

六、内存的使用和释放

【C#】内存的使用和释放

相关推荐
翔云 OCR API3 小时前
发票查验接口详细接收参数说明-C#语言集成完整示例-API高效财税管理方案
开发语言·c#
虫小宝4 小时前
高佣金的返利平台性能压测:从单接口到全链路的性能瓶颈分析
c#·linq
故事不长丨5 小时前
C#集合:解锁高效数据管理的秘密武器
开发语言·windows·c#·wpf·集合·winfrom·字典
jghhh016 小时前
基于C#实现与三菱FX系列PLC串口通信
开发语言·算法·c#·信息与通信
故事不长丨7 小时前
C#队列深度剖析:解锁高效编程的FIFO密码
visualstudio·c#·wpf·多线程·winfrom·队列·queue
bugcome_com7 小时前
C# 反射(Reflection)超全解析
c#
bjzhang759 小时前
Dorisoy.AMS--一款采用C# WinForm框架+SQLite数据库的企业/机构资产管理解决方案
sqlite·c#·资产管理
零度@10 小时前
Java消息中间件-Kafka全解(2026精简版)
java·kafka·c#·linq
2501_9418824811 小时前
在开普敦跨区域部署环境中构建高可靠分布式配置中心的设计思路与实现实践
开发语言·c#
zxy284722530112 小时前
利用C#的BotSharp本地部署第一个大模型AI Agent示例(1)
人工智能·c#·对话·ai agent·botsharp