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
相关产品推荐
相关产品推荐

