You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#串口接收场景下反复赋值字符串是否会引发内存泄漏?

代码内存风险与问题分析

内存泄漏判定

这段代码不存在传统意义上的内存泄漏风险。
C#中string是不可变引用类型,每次给静态变量TemporaryData赋值新的接收数据时,之前存储的旧字符串如果没有被其他代码持有引用,会被GC垃圾回收器正常识别并回收,不会出现内存持续占用无法释放的泄漏问题。

实际存在的内存负面影响

虽然没有内存泄漏,但在串口持续高频发送数据的场景下,这段代码会带来明显的性能损耗:

  • DataReceivedHandler事件会被高频触发,每次触发都会生成新的字符串对象,旧值被覆盖后成为待回收的垃圾对象,会产生大量短命堆分配
  • 高频的小对象分配会频繁触发GC回收,占用额外CPU资源,数据量较大时可能导致程序卡顿、串口数据接收丢包

更严重的功能逻辑问题

比内存问题优先级更高的是代码的逻辑bug:

  • 每次接收数据直接覆盖TemporaryData变量,如果业务处理代码没来得及在上次接收和下次接收的间隙读走数据,上一次的数据会直接丢失,完全无法适配串口数据分片到达的特性
  • DataReceivedHandler运行在线程池线程上,静态变量的读写没有加线程同步锁,多线程竞争下会出现数据读写混乱的问题

优化参考实现

可以用可复用的StringBuilder做接收缓存,搭配锁保证线程安全,减少字符串重复分配的开销,同时避免数据覆盖丢失:

// 可复用的接收缓存,避免频繁生成新字符串对象
private static readonly StringBuilder TemporaryDataBuffer = new StringBuilder();
// 线程同步锁
private static readonly object DataLockObj = new object();

private static void DataReceivedHandler(
    object sender,
    SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    string indata = sp.ReadExisting();
    lock (DataLockObj)
    {
        // 追加新收到的数据,而不是直接覆盖
        TemporaryDataBuffer.Append(indata);
    }
    // 可在此处添加信号通知,唤醒业务线程处理已接收的数据
}

/// <summary>
/// 读取并清空当前缓存的所有接收数据
/// </summary>
public static string GetAndClearReceivedData()
{
    lock (DataLockObj)
    {
        string res = TemporaryDataBuffer.ToString();
        TemporaryDataBuffer.Clear();
        return res;
    }
}

内容的提问来源于stack exchange,提问作者DmO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 07:18:16