Hi.
I communicate
with the serial port on my ”PDA/smart device” to another device (custom circuit board). The PDA
needs to send data at least once a second to the hardware just to confirm that
there is a connection; If not the hardware shuts down. The PDA also receives
information from the device witch is displayed.
The problem
is that when the PDA receivea data, the application starts to leak
memory. After 30 minutes to an hour the garbage collection procedure takes so
much time that the communication halts for several seconds, witch in turn
causes a timeout.
Could there be a problem in the SerialPort.Receive() or in the garbage collector. Most likely I have done something wrong…
Here is a simplified
version of the communication, but it suffers the same problems.
If you try it,
the leak could take a minute before the memory starts to leak.
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace MemoryLeak
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
label1.Text = "MEM:"+ (GC.GetTotalMemory(true)/1024)+ "kB";
label2.Text = "MEM:" + GC.GetTotalMemory(true) + "B";
if (serialPort1.IsOpen)
{
SendTrashToKeepCommunicationRunning(); // hardware needs to get data in order to send data.
byte[] tempArray = new byte[3000];
int bytesToRead = serialPort1.BytesToRead;
serialPort1.Read(tempArray, 0, bytesToRead);
// Process incoming data..
tempArray = null; // Should also go out of scope and be collected by the GC
}
}
private void button1_Click(object sender, EventArgs e)
{
serialPort1.Open();
timer1.Enabled = true;
}
private void button2_Click(object sender, EventArgs e)
{
timer1.Enabled = false;
serialPort1.Close();
}
private void SendTrashToKeepCommunicationRunning()
{
byte[] D = new byte[14];
D[0] = 255;
D[1] = 170;
D[2] = 31;
D[3] = 8;
D[4] = 0;
D[5] = 0;
D
D[7] = 0;
D
D[9] = 0;
D[10] = 0;
D[11] = 8;
// Checksum
D[12] = Convert.ToByte((D[0] + D[1] + D[2] + D[3] + D[4] + D[5] + D
D[13] = Convert.ToByte((D[0] + D[1] + D[2] + D[3] + D[4] + D[5] + D
if (serialPort1.IsOpen)
{
serialPort1.Write(D, 0, 14); // send data
serialPort1.Write(D, 0, 14); // send data
}
D = null; // Should also go out of scope and be collected by the GC
}
}
}

Memory leak in SerialPort.Read?
gripusa
is that your code has no loops and acts only for events.
Simplifyed example = no loops
Real app = loops (I have a separate thread running to handle send and receive calls, = loop)
the problem in SerialPort is, that the Read()-method calls a buffer which is everytime used from the other station until the bluetooth connection is open.
I do not understand, could you clarify what you mean by “station”. I realise that the SerialPort has its own buffer, and returns data from it when SerialPort.Read() is called.
So if you set the "tempArray = null" and the GC see that the other station is still using this buffer und you set this to null then you have a problem. (is not Thread safe) Thats the reason because Serial Port must be used everytime over Delegates and with the Method string serialPort.ReadToEnd();
Still not following what you mean by “station”, and i can not find a method serialPort.ReadToString(); in C#. Could you give a short example
Attention: read the book about WinCE because every loop in WinCE is one Loop to much. It stops the possibility to let the CPU take the Hibernate-State to save Energy. For the following Code:
application.start()
While !( UserPressExit ) { ... }
application.exit()
This is very bad because this code makes busy wating and the battery is in some hours empty.
I see your point! My real application will have only little idle time since it is more important to lower the communication delays instead.
Vijay Guru Prasadh
- What's timer1's interval
- At what rate do you see GC.GetTotalMemory() increasing
- What do you do in "// Process incoming data"
- What happens when you make the D[] and tempArray[] buffers class members
andyr2005
Chris,
That looked like stuff for the desktop. I have the problem in the compact framework.
The leak is in the serialport.readexisting line.
Thanks
QuinDennis
Mike, please post your question on the .NET CF forums for help:
http://forums.microsoft.com/MSDN/ShowForum.aspx ForumID=33&SiteID=1
-Chris
Scott Boyd
Hi Kristian
There's a great blog post by Performance guru Rico Mariani that can help you track down your managed memory leak:
http://blogs.msdn.com/ricom/archive/2004/12/10/279612.aspx
Hope that helps
-Chris
Michael J Brown
Mike
Did the article I linked to not indicate where the leak could be How are you measuring the memory leak
-Chris
Fyrus
sorry for my terrible answer. i'm busy...
so again: you are rigth programs should have loops but in Applications on WinCE is each loop like While(true){} so led a for example a worker thread do this job terrible!
with serial port you can use different strategien.
1. polling: this is "while(true){...}"
2. event driven
use the delegate from serial port (i think it was called dataReceived) object. if you do this you can use the method readToEnd() from serial port. the method return a string and not byte. it's user friendly to read.
bye
Musafir
This thread is very interesting as when I use .NETCF2 SP1 serial port class, my application leaks a lot.
Basically, I have a GPS device on an IPAQ 2210 connected via a serial cable into com1.
I use the Receive event to start a new thread. Once in it, I loop round checking for data.
While not the most elegant of ways to do it, it stops new threads being created / exited every second.
The port.ReadExisting seems to leak a few KB every 10 seconds or so.
Any ideas SP1 applied to VS2005 and handheld.
Thanks
Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using System.IO.Ports;
using System.Threading;
namespace DeviceApplication1
{
public partial class Form1 : Form
{
private SerialPort port = new SerialPort("COM1:", 57600, Parity.None, int.Parse("8"), StopBits.One);
public Form1()
{
InitializeComponent();
Start();
}
private void Start()
{
port.ReceivedBytesThreshold = 1;
port.DtrEnable = false;
port.Handshake = Handshake.None;
port.WriteBufferSize = 500;
port.WriteTimeout = 2000;
port.DataReceived += new SerialDataReceivedEventHandler(port_DataReceived);
port.Open();
}
private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//now this thread is active, turn off threshold
port.ReceivedBytesThreshold = 999999;
string Buffer = "";
try
{
//Just continue reading port on this new thread
while (port.IsOpen)
{
Buffer = port.ReadExisting();
Debug.WriteLine("MEM:" + (GC.GetTotalMemory(true) / 1024) + "kB");
Thread.Sleep(50);
}
}
catch (Exception ex)
{
Debug.WriteLine("Error:" + ex.Message);
}
}
}
}
AlfonsAberg
Reese Bird
Thank you all for your time.
Timer1 interval = 300 ms
GC.GetTotalMemory() increases with 280 kB/minute.
“Process incoming data” does nothing in the example.
D[] and TempArray[] as class members does not help. Still leaking memory.
(The real application that I have developed would benefit from real time behaviour. But since there is no guarantee for this with in .Net, I have tested several methods to get a more stabile communication delay. This is best achieved with a separate (high priority) thread instead of relying on events. When using events the time between sent protocols is very sporadic, and could easily cause the application to time out. I realise that this is not the best way to do communication, and an application without my special needs would work much smoother with an event driven communication.)
adorer
The best way to communicate over serial port is to use events or delegates. The advantage is that your code has no loops and acts only for events. the problem in SerialPort is, that the Read()-method calls a buffer which is everytime used from the other station until the bluetooth connection is open.
So if you set the "tempArray = null" and the GC see that the other station is still using this buffer und you set this to null then you have a problem. (is not Thread safe) Thats the reason because Serial Port must be used everytime over Delegates and with the Method string serialPort.ReadToEnd();
Attention: read the book about WinCE because every loop in WinCE is one Loop to much. It stops the possibility to let the CPU take the Hibernate-State to save Energy. For the following Code:
application.start()
While !( UserPressExit ) { ... }
application.exit()
This is very bad because this code makes busy wating and the battery is in some hours empty.
bye patrick