分类 编程 下的文章

在 C# 中,内存优化是提升应用性能和稳定性的关键。以下是常见的内存优化方法,结合示例和最佳实践:

一、对象分配与生命周期优化

1. 减少临时对象创建

  • 问题:频繁创建短生命周期对象会导致 GC 压力增大。

  • 优化方法

    • 使用StringBuilder替代字符串拼接(尤其在循环中)。
    • 复用对象实例(如使用对象池)。

    示例(反例)

    string result = "";for (int i = 0; i < 1000; i++) {    result += i.ToString(); // 每次拼接创建新字符串}

    优化后

    StringBuilder sb = new StringBuilder();for (int i = 0; i < 1000; i++) {    sb.Append(i); // 复用StringBuilder实例}string result = sb.ToString();

2. 使用值类型替代引用类型

  • 场景:频繁创建的小型对象(如坐标点、状态标志)。

  • 优化方法

    • 使用struct替代class
    • 使用Span<T>/Memory<T>避免内存分配。

    示例

    public readonly struct Point { // 值类型    public double X { get; }    public double Y { get; }        public Point(double x, double y) => (X, Y) = (x, y);}

3. 避免装箱拆箱

  • 问题:值类型与object之间的转换会产生临时对象。

  • 优化方法

    • 使用泛型集合(如List<T>)替代非泛型(如ArrayList)。
    • 使用System.ValueTuple替代早期的Tuple类。

    示例(反例)

    ArrayList list = new ArrayList();list.Add(42); // 装箱:int → objectint value = (int)list[0]; // 拆箱:object → int

    优化后

    List<int> list = new List<int>();list.Add(42); // 直接存储int,无装箱int value = list[0]; // 无拆箱

二、集合与数组优化

1. 预分配集合容量

  • 问题:动态扩容会导致内存复制和旧数组垃圾。

  • 优化方法

    • 使用带初始容量的构造函数(如new List<int>(100))。

    示例

    // 预分配足够容量,避免多次扩容var users = new List<User>(1000); 

2. 使用高效集合类型

  • 场景:根据访问模式选择合适的集合。

  • 推荐类型

    • Dictionary<TKey, TValue>:快速查找(O (1))。
    • HashSet<T>:唯一元素集合。
    • ConcurrentDictionary<TKey, TValue>:线程安全的字典。

    示例

    // 使用字典替代List,提升查找性能var userMap = new Dictionary<int, User>();userMap.TryGetValue(userId, out var user); // O(1)时间复杂度

3. 避免大型稀疏数组

  • 问题:大量空元素的数组浪费内存。
  • 优化方法
    • 使用Dictionary<int, T>SparseArray(需自定义)。

三、内存管理与垃圾回收

1. 控制对象生命周期

  • 原则:及时释放不再使用的资源。

  • 方法

    • 使用using语句管理实现IDisposable的对象。
    • 避免静态集合持有大量对象引用。

    示例

    using (var stream = new FileStream("data.txt", FileMode.Open)) {    // 使用stream...} // 自动调用Dispose()释放资源

如何搭建一套数据采集系统?
Neuron 实现多协议设备接入。
MQTT 协议进行数据传输。
EKuiper 是一个轻量级边缘流处理引擎,专为物联网(IoT)边缘场景设计,进行边缘计算。
TDengine 时序数据库实现高效存储与分析。
如何搭建一套半实物仿真系统?
VerStand 是汽车与嵌入式实时仿真的核心工具,与 Matlab 深度集成,解决 HIL 测试的场景化需求。
LabVIEW 以硬件控制与快速开发见长,适合构建定制化测试系统,与 TestStand 结合可实现从研发到量产的测试流程复用。
Matlab 作为算法开发的 “基础设施”,通过代码生成技术可将原型无缝部署至实时平台或嵌入式设备。
TestStand 则像 “胶水” 一样,将不同工具、硬件和测试步骤串联起来,提升大规模测试的效率与可靠性。

ManualResetEvent被用于在 两个或多个线程间 进行线程信号发送。

多个线程可以通过调用ManualResetEvent对象的WaitOne方法进入等待或阻塞状态。当控制线程调用Set()方法,所有等待线程将恢复并继续执行。

以下是使用ManualResetEvent的例子,确保多线程调用时 First->Second->Third 的顺序不变。若看完仍有疑惑,请点击传送门

using System.Threading;

public class Foo {

private readonly ManualResetEvent firstDone = new ManualResetEvent(false);
private readonly ManualResetEvent secondDone = new ManualResetEvent(false);    

public Foo() {
    
}

public void First(Action printFirst) {
    
    // printFirst() outputs "first". Do not change or remove this line.
    printFirst();
    firstDone.Set();
}

public void Second(Action printSecond) {
    firstDone.WaitOne();
    // printSecond() outputs "second". Do not change or remove this line.
    printSecond();
    secondDone.Set();
}

public void Third(Action printThird) {
    secondDone.WaitOne();
    // printThird() outputs "third". Do not change or remove this line.
    printThird();
}
}