Main Site Documentation

Memorie usage COM-port


#1

In my project I use COM2. I connect it with the pc via a TTL-232R-3V3 cable.
Before any message is sent, the GC says:
GC: 1msec 19752 bytes used, 44628 bytes available
But every time I send bytes, it consumes a little memory.
after about 40 messages there is not enoufh memory to allocate.
GC: 8347 bytes available.

The Port doesn’t receive any data from then.
I am sure the memory leak is not in the other code, because, I have another thread, sleeping and sometimes(every sec) looking if the variable "geheugenVol"is true.
then the serial port is disposed, and assign new again. The memory is back at 44kB.

all the consumed memory is in:
Type 1E (BINARY_BLOB_HEAD )

Could someone please tell me how do clean my memory proper, instead of disposing my port?

I use the code below, but I deleted the code between the cases 5, 6 and 7.


static byte[] buffer1 = new byte[1];
static void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] buffer2, buffer3;
            if (port != null)
            {
                if (!geheugenVol)
                {
                    int aantal = port.Read(buffer1, 0, 1);
                    switch (buffer1[0])
                    {
                        case 1://enkele bitstream
                            buffer2 = new byte[44];
                            buffer2[0] = buffer1[0];
                            port.Read(buffer2, 1, 43);
                            port.Write(new byte[] { 10 }, 0, 1);                          
                            if (!BEzig)//is set in "AfstandBediening"
                            {
                                AfstandBediening(buffer2);
                                port.Write(new byte[] { 12 }, 0, 1);
                            }

                            break;
                        case 3:
 buffer2 = new byte[2];                            
                            port.Read(buffer2, 0, buffer2.Length);                        
                            int grootte = (buffer2[0] * 255) + buffer2[1];                    
                            buffer3 = new byte[grootte + 2];                            
                            port.Read(buffer3, 2, buffer3.Length - 2);                            
                            buffer3[0] = buffer2[0];
                            buffer3[1] = buffer2[1];                            
                            VoegTijdschemaToe(buffer3);                            
                            buffer3 = null;
                            buffer2 = null;
                            Debug.GC(true);
                            port.Write(new byte[] { 15 }, 0, 1);
                            break;
                      
                        case 5://verwijder tijdschem
                            buffer2 = new byte[2];
                            port.Read(buffer2, 0, buffer2.Length);
                            if (buffer2[0] == buffer2[1])
                            {
                                port.Write(new byte[] { 10 }, 0, 1);
                                VerwijderTijschemas();
                                port.Write(new byte[] { 14 }, 0, 1);

                            }
                            break;
                        case 6://zet correcte tijd
                            buffer2 = new byte[6];
                            port.Read(buffer2, 0, buffer2.Length);
                            DateTime time = new DateTime(((int)buffer2[2] + 2000), (int)buffer2[1], (int)buffer2[0], (int)buffer2[3], (int)buffer2[4], (int)buffer2[5]);
                            Utility.SetLocalTime(time);
                            port.Write(new byte[] { 16 }, 0, 1);
                            break;
                        case 7://ping
                            port.Write(new byte[] { 9 }, 0, 1);//ping back 
                            BEzig = false;
                            break;
                        default:
                            port.Write(new byte[] { 17 }, 0, 1);
                            break;

                    }
                    buffer2 = null;
                    buffer3 = null;
                    port.Flush();
                    port.DiscardInBuffer();
                    port.DiscardOutBuffer();

                    Debug.GC(false);
                }
                uint a = Debug.GC(true);
                if (a < 20000)
                {
                    geheugenVol = true;
                }


            }
        }

#2

Please provide a simple and complete program that shows this behavior.

There is nothing for you to worry about, GC cleans up everything automatically. If you otherwise then we need a simple program that we can use to track the problem


#3

I will try to make a simple program that has the same problem, I will post it in a few days.
Thanks for the quick respond!


#4

The port.read() method ends when the requested number of bytes are read OR the port has been idle for the read timeout period.

The default read timeout is 500ms.

You do not check the number of characters that are read… You might not be getting the number of characters that you are expecting.

Also you are discarding the contents of the input and output port buffers. Why? Is it possible that
you are losing data in the input buffer?

I think you should put some Debug.Print statements in your code and see what is happening. Print out the bytes that contain lengths. I think you might find your problem.

I suspect the memory depletion is due to you miss reading the data stream.


#5

Hello

Can you try something like that…
Of course for the port I didn’t set up BaudRate etc… as I don’t know your settings.

This code is for your incoming data to the serial port, as you don’t consume the all buffer you might miss something.

About your memory leak, My guts feeling is that .NETMF does’t like your discard methods. The only way (well I think) to avoid memory leak is to use the Close() method of the serial port when you don’t need it anynmore. But leaving it open should not create a leak.

I hope it works (couldn’t test it }:stuck_out_tongue: ) and helps

Cheers

public class Program
    {
        static SerialPort port = new SerialPort("COM2");
        public static void Main()
        {
           port.DataReceived+=new SerialDataReceivedEventHandler(Test_DataReceived);
        }

        static void Test_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
           //create the array according to the numb of byte to read into the buffer
            byte[] buf = new byte[port.BytesToRead];
          //read the entire buffer
            port.Read(buf, 0, port.BytesToRead);
        

            //print the byte to check
            string myPrintBuf = ""; 
            for (int i = 0; i < buf.Length; i++)
            {
                myPrintBuf += buf[i] + "|";
            }
            Debug.Print(myPrintBuf);


            switch (buf[0])
            {
                case 1:
                    port.Write(new byte[] { 10 }, 0, 1);
                    if (!BEzig)//is set in "AfstandBediening"
                    {
                        byte[] buffer2 = new byte[buf.Length-1];
                        Array.Copy(buf,1,buffer2,0,buf.Length-1);
                        AfstandBediening(buffer2);
                        port.Write(new byte[] { 12 }, 0, 1);
                    }

                    break;
               
                 case 2:
                   //etc....
                   break;

            }

#6

Our internal system drivers should protect itself from improper use and so never leak any memory. If you manage to leak memory then we would need a small program that demonstrates this problem so we can track and fix.


#7

I spent much of this weekend troubleshooting as bug and I’m pretty sure I’ve just confirmed there is a problem, and it looks like it’s with the SerialPort class.

if you build an event handler like so:

        
static public Queue buff = new Queue();

private static void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            while (UART.Read(rx_byte, 0, 1) > 0) // do we have data?
             {
                buff.Enqueue(rx_byte[0]);
              }
        }

you’ll lose memory to the BLOB pool. I’ve actually seen it in the debugger spin with only one byte to read entering the same byte in the queue buff, and the serial port read returns the same byte repeatedly. Each call to the event handler allocates a seeming random amount of memory sometimes 1 or 10 bytes, sometimes thousands. The Queue buff does not seem to grow.

On the other hand:


private static void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int todo = 0;
            todo = UART.BytesToRead;
            for (int i = 0;i<todo;i++)
            {
                UART.Read(rx_byte,0,1);
                buff.Enqueue(rx_byte[0]);
              }
        }    

code which looks much less efficient(and is), doesn’t loose memory. Both event handler return the correct data from the serial port when finished. Both are Kosher, and I’ve used variations of the top version for years.


#8

That is not a bug. If you do not empty the uart by reading all data then this data will eat memory. The event should only used as a way of knowing data is ready and then you should always read all the data. If you are thinking C then this is not an RX ISR


#9

Gus,

First, thanks for your response. Now forgive me if I’m being thick headed, but your points don’t seem to hold water.

If you look closely at the code you’ll see it will empty the UART, it just does it one byte at a time. As a mattter of fact it’s almost the same as the example code from page 79 of the getting started book:


SerialPort UART =new SerialPort("COM1", 115200); 
int read_count = 0; 
byte[] rx_byte = new byte[1];
while(true) 
{ // read one byte 
   read_count = UART.Read(rx_byte, 0, 1);
   if (read_count > 0)// do we have data? 
      { // create a string 
       string counter_string = "You typed: " + rx_byte[0].ToString() + "\r\n"; // convert the string to bytes 
       byte[] buffer =Encoding.UTF8.GetBytes(counter_string); // send the bytes on the serial port 
       UART.Write(buffer, 0, buffer.Length); //wait... Thread.Sleep(10);   
     }
}

read_count = UART.Read(rx_byte, 0, 1);
if (read_count > 0)// do we have data?

while (UART.Read(rx_byte, 0, 1) > 0)

My code is functionally an almost exact copy, except it’s a little tighter, because I combined the two bolded lines into one statement, and instead of putting the byte I read into a string I put it into a queue. So if your evaluation of my code is correct, this sample is incorrect and should loop eating thousands of bytes for each call?

In any case this still doesn’t explain the behavior of the UART where reading single bytes from it’s queue causes it to loop and eat 20K before ultimaterly returning with the correct value. The serial communication I’m doing involves sending 1 to four bytes and receiving one byte as a return message, and Ack or Nack. That’s the sum total, and I was running at 9600 baud, in a single thread. Now on the new code I wrote runs at 115k baud with no issues, it’s been running a test ptogram for about four hours.

Thanks again, and please don’t take any thing personally, I just want to have other people avoid spending an entire weekend debugging code that should work, and is the functionally the same as the getting started sample. I’m a relative newcomer programming since 1978, and doing .net desk top for the last 6 years.

mike.


#10

Can you provide a complete but simple application that demonstrates the problem please?