Reputation: 1689
I'm trying to use the following to continuously read data from a serial port:
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);
}
This leaks memory with an ever-increasing number of the following objects:
The objects persist even after a garbage collection pass.
The sample above is a minimal reproducible example. I've taken out the "do something with data" because the problem occurs with or without any data handling at that point.
The Thread.Sleep
in the while loop only slows down memory consumption. I've left it out so that it clearly shows the problem. The above sample will consume approximately 650mb in 20 seconds on my machine.
The problem occurs in both .NET Core 3.1 and .NET Framework 4.8.
I'm sure I'm doing something wrong, I just can't see what it is at this point.
Upvotes: 1
Views: 329
Reputation:
This leaks memory with an ever-increasing...
Quite simply because you are infinitely looping BeginRead
operations before the existing one has completed via:
while (true)
{
read(); // <-- this delegate calls `BeginRead` thus starting ANOTHER verlapped read operation
//Thread.Sleep(100);
}
Change it to something like:
serialPort.Open();
read(); // kick off initial read
while (/* some condition*/)
{
}
// quit
Your callback is doing the right thing by ensuring that another overlapped read operation is only commenced once the prior completes:
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
};
Upvotes: 1