我正试图使用以下方法从串行端口连续读取数据:
var serialPort = new SerialPort("COM7", 38400, Parity.None, 8, StopBits.One);
var buffer = new byte[256];
Action read = null;
AsyncCallback callback = delegate (IAsyncResult ar)
{
int len = serialPort.BaseStream.EndRead(ar);
// do something with data
read();
};
read = delegate
{
serialPort.BaseStream.BeginRead(buffer, 0, buffer.Length, callback, null);
};
serialPort.Open();
while (true)
{
read();
//Thread.Sleep(100);
}
这会随着以下对象数量的增加而泄漏内存:
- 手动重置事件
- 微软。Win32.SafeHandles.SafeWaitHandle
- ThreadPoolBoundHandleOverlapped
- 重叠的数据
- SerialStream+SerialStreamAsyncResult
即使在垃圾收集通过后,对象仍然存在。
上面的样品是一个可重复性最小的例子。我去掉了"用数据做点什么",因为无论当时是否进行任何数据处理,问题都会出现。
while循环中的Thread.Sleep
只会降低内存消耗。我把它省略了,这样它就清楚地表明了问题所在。在我的机器上,上述样本将在20秒内消耗大约650mb。
这两种情况都会出现问题。NET Core 3.1和。NET Framework 4.8。
我确信我做错了什么,只是我现在看不出是什么。
这会随着。。。
很简单,因为在现有操作通过完成之前,您正在无限循环BeginRead
操作
while (true)
{
read(); // <-- this delegate calls `BeginRead` thus starting ANOTHER verlapped read operation
//Thread.Sleep(100);
}
将其更改为类似的内容
serialPort.Open();
read(); // kick off initial read
while (/* some condition*/)
{
}
// quit
您的回调通过确保另一个重叠读取操作仅在前一个操作完成后才开始来做正确的事情:
AsyncCallback callback = delegate (IAsyncResult ar)
{
int len = serialPort.BaseStream.EndRead(ar);
// do something with data
read(); // <--- correctly initiates another read since the existing is complete
};