C# SerialPort memory issues when disconnecting the device
-
Wednesday, June 27, 2012 9:48 AM
Hi,
I try to implement an application that track a laptop using an external GPS device. In order to make some test, I wrote dummy code that configure a comport, and add a DataReceivedEventHandler to it.
All works fine but when I decide to unplug the GPS device, the memory use by the process grow up continually. In the future I would like to be able to unplug and plug GPS device when I want.I'm not an expert in Serial Port application, do you have an idea of how to manage this problem?
regards,
All Replies
-
Wednesday, June 27, 2012 11:31 AM
Not a common problem. Rewrite your code to avoid the memory leak.- Proposed As Answer by Mike FengMicrosoft Contingent Staff, Moderator Friday, June 29, 2012 12:50 PM
- Marked As Answer by Mike FengMicrosoft Contingent Staff, Moderator Sunday, July 08, 2012 9:43 AM
-
Wednesday, June 27, 2012 11:48 AM
My code is quite simple, at the moment only this two functions:
private void Form1_Load(object sender, EventArgs e)
{
comport = new SerialPort("COM3", 4800, Parity.None, 8, StopBits.One);
comport.DataReceived += new SerialDataReceivedEventHandler
(gpsDataReceived); if (comport.IsOpen == true)
comport.Close();
comport.Open();
}
void gpsDataReceived(object sender, SerialDataReceivedEventArgs e)
{
string data = comport.ReadExisting();
//TO DO : Parsing
}
How should I manage when I remove the device?
-
Wednesday, June 27, 2012 12:02 PMYour problem isn't in the code you posted.
-
Wednesday, June 27, 2012 12:05 PM
See the remark section of the webpage below with regards to hardware handshaking. When you remove the device the clear to send should get removed ifg the hardwae is set properly. what is probably happening is one of the harrdware signals isn't pull to active off state in the device driver so you are getting noise and causing the memory leak. In you software you should be able to set the hardwarre handshaking. then when the device is removed you can set an event handler to recognize when the device is removed and close the interface.
http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.handshake
jdweng
-
Thursday, June 28, 2012 7:32 AM
Why does everybody copy the same mistake?
if (comport.IsOpen == true)
comport.Close();
comport.Open();
}
If the port is already open when you enter the code, the port is closed and reopened immediately after, which is not allowed. SerialPort has a background thread, which needs in the order of 200 ms to close down. Put at least a Sleep(200) between any close and open statement and perhaps an Application.DoEvents() before the Sleep statement to make it invisible to the user.
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
-
Thursday, June 28, 2012 8:39 AM
Why does everybody copy the same mistake?
if (comport.IsOpen == true)
comport.Close();
comport.Open();
}
If the port is already open when you enter the code, the port is closed and reopened immediately after, which is not allowed. SerialPort has a background thread, which needs in the order of 200 ms to close down. Put at least a Sleep(200) between any close and open statement and perhaps an Application.DoEvents() before the Sleep statement to make it invisible to the user.
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
You posted the code out of context:
private void Form1_Load(object sender, EventArgs e)
{
comport = new SerialPort("COM3", 4800, Parity.None, 8, StopBits.One);
comport.DataReceived += new SerialDataReceivedEventHandler(gpsDataReceived);
if (comport.IsOpen == true)
comport.Close();
comport.Open();
}
How does the code you find fault with get executed?I also don't see how following Open immediately after Close can cause any problems. Close waits for the thread to end before returning.
-
Thursday, June 28, 2012 9:23 AM
Maybe I have taken the code out of context, but if you make a new port and therefore know for sure that it is closed, why make the test "If (comport.IsOpen == true)"?
Due to an "Unknown error", I have never been able to install .Net 4.0, so I cannot tell if that version waits for the background thread to close down before returning, but none of the previous versions did, and you got en error, if you tried to reopen the port immediately after a close.
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
-
Thursday, June 28, 2012 10:07 AM
"none of the previous versions did, and you got en error, if you tried to reopen the port immediately after a close."
The 2.0 port also waits for the thread to close before return from Close(). It may be possible to get an error depending upon how the Events are coded.
This code targets .NET 2.0 and runs without error when the Cycle button is pressed:
Imports System.IO.Ports
Imports System.Windows.Forms
Public Class Form1
Inherits Form
Dim MS As New MenuStrip
Dim MSLbl As New ToolStripLabel
Dim MSCycle As New ToolStripButton("Cycle")
Dim TB As New TextBox
Dim PortName As String = "COM3"
Dim SP As New SerialPort(PortName, 4800)
Sub New()
MS.Items.Add(MSCycle)
AddHandler MSCycle.Click, AddressOf MSCycle_Click
MS.Items.Add(MSLbl)
MS.Parent = Me
TB.Multiline = True
TB.Parent = Me
TB.BringToFront()
TB.Dock = DockStyle.Fill
If Array.IndexOf(SerialPort.GetPortNames, PortName) >= 0 Then
SP.Open()
MSLbl.Text = "Open"
Else
MSLbl.Text = "Closed"
End If
End Sub
Delegate Sub CyclePortDelegate()
Sub CyclePort()
For I As Integer = 0 To 99
If SP.IsOpen Then
SP.Close()
MSLbl.Text = "Closed"
Else
SP.Open()
MSLbl.Text = "Open"
End If
MS.Refresh()
Next
End Sub
Sub MSCycle_Click(sender As Object, e As EventArgs)
Me.BeginInvoke(New CyclePortDelegate(AddressOf CyclePort))
End Sub
End Class
This post is incorrect. It doesn't target .NET 2.0. I'll leave it here until I verify it one way or the other.
I replaced the code with .NET 2.0 code. It still performs the same, as it should because the code for closing and opening the stream is the same in .NET 2.0 and .NET 4.0. Closing of the port isn't as simple as is done in this code. Closing the port, which closes the stream and ends the event handler thread, while the code is executing on the UI thread in a method called from the thread locks the program.
- Edited by JohnWeinMicrosoft Community Contributor Thursday, June 28, 2012 10:37 AM
- Edited by JohnWeinMicrosoft Community Contributor Thursday, June 28, 2012 11:02 AM
-
Thursday, June 28, 2012 12:03 PM
Just a few examples of problems due to open immediately after close:
"Closing the port, which closes the stream and ends the event handler thread, while the code is executing on the UI thread in a method called from the thread locks the program."
There is a possiblility for a dead-lock if you use Invoke, but I have never seen a reason why this dead-lock should occur with BeginInvoke.
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
-
Thursday, June 28, 2012 12:22 PM
Have you looked at your links? One reports problems using multiple threads of the coders own making. The other reports problems using CreateFile to open COM ports. How does either link relate to this discussion. And how does this discussion relate to this thread? I've used a GPS for testing the SerialPort since 2007 and never had a memory issue with any code, certainly not with the code the OP posted.Just a few examples of problems due to open immediately after close:
"Closing the port, which closes the stream and ends the event handler thread, while the code is executing on the UI thread in a method called from the thread locks the program."
There is a possiblility for a dead-lock if you use Invoke, but I have never seen a reason why this dead-lock should occur with BeginInvoke.
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
-
Thursday, June 28, 2012 1:33 PM
OK, here is a link from the horses own mouth: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.close.aspx
Note the remark:
"The best practice for any application is to wait for some amount of time after calling the Close method before attempting to call the Open method, as the port may not be closed instantly."
Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.
-
Thursday, June 28, 2012 4:36 PMSo there is really no reason other than the Docs say it's good practice for some reason. Close, closes the stream and ends the thread before it returns. There is no reason that I can think of that the stream can't be opened and a thread started anythime after the call to Close returns.
-
Friday, June 29, 2012 12:53 PMModerator
Hi,
I try to implement an application that track a laptop using an external GPS device. In order to make some test, I wrote dummy code that configure a comport, and add a DataReceivedEventHandler to it.
All works fine but when I decide to unplug the GPS device, the memory use by the process grow up continually. In the future I would like to be able to unplug and plug GPS device when I want.I'm not an expert in Serial Port application, do you have an idea of how to manage this problem?
regards,
Hi Julien,
Welcome to the MSDN Forum.
I agree with John, please check your code again, especially the code handles the event when a device is unplug.
Best regards,
Mike Feng
MSDN Community Support | Feedback to us
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
-
Friday, June 29, 2012 3:04 PMThe event will not work unless the hardware controls are enabled, the cables has the wires, and wired in the serial device.
jdweng
-
Monday, July 02, 2012 10:12 AM
Hi,
I don't have code to handle when the device is unplugged, I don't know how to do it, it is a part of my question. (Should I listen USB port? or try to catch an event?)
I was hoping that when the device is disconnected, dataReceived event will not be called again and then the pocess will end. I m very astonished to see memory growing up like this because there is no loop, and dataReceived is not called anymore, I don't understand where is the memory leak.
Thanks for all your anwers.
Julien
-
Monday, July 02, 2012 11:30 AM
You need to close the port to prevent the memory leak. You probably need to capture the hardware event sown in the webpage below. Use the DSR or CTS event. Add the close method to the event handler.
http://msdn.microsoft.com/en-us/library/system.io.ports.serialpinchange
I found one sample of using this code, but the person never tested this code
private void serialPort1_PinChanged(object sender, System.IO.Ports.SerialPinChangedEventArgs e)
{
if (e.EventType == System.IO.Ports.SerialPinChange.Ring)
{
string data = serialPort1.ReadExisting()
}
}I also found this webpage
http://www.wxforum.net/index.php?topic=13693.10;imode
jdweng
-
Monday, July 02, 2012 11:57 AM
"I don't understand where is the memory leak."
Remove the code you posted and you should still have the memory leak.
-
Monday, July 02, 2012 2:19 PM
JohnWein,
There is no other code! , it's a dummy windows app, in the form_load function, I instantiate a SerialPort object and then call the method Open on it.
After that, I physically remove the USB Device and the memory begin to grow up.
If I try to close de SerialPort (using a button), an exception is raised (IOException: the device doesn't recognize the command).
-
Monday, July 02, 2012 2:42 PM
JohnWein,
There is no other code! , it's a dummy windows app, in the form_load function, I instantiate a SerialPort object and then call the method Open on it.
After that, I physically remove the USB Device and the memory begin to grow up.
If I try to close de SerialPort (using a button), an exception is raised (IOException: the device doesn't recognize the command).
With the information you have proviced, your results cannot be reproduced. Disconnecting a USB - Serial converter for SerialPort 4.0 and earlier will result in known problems, not one of which is a memory leak. The only reliable .NET SerialPort is the 2.0 version, which can easily be closed after the converter is disconnected by closing the port and catching the error.

