OutOfMemoryException

I’m working with GPS receiver and I’m parsing the NMEA sentences.
I receive

Exception System.OutOfMemoryException - CLR_E_OUT_OF_MEMORY (4)

after a very short time (less than a minute or two)
First I used C# functions to handle the strings and then I wrote a function by myself but it didn’t help.

Here is a sample of my code:


static void SerialUSBThread()
{
byte[] data = new byte[128];
int len;

string buffer = "";
string sentence = "";

try
{
     while (true) 
     {
           len = serialUSB.Read(data, 0, 128);

           for (i = 0; i < len - 1; i++) 
           {
                buffer += array[i];
           }

            for (i = 0; i < len; )
           {                        
                   // find start of a sentence                
                   startIndex = buffer.IndexOf('$', i);

                   if (startIndex == -1)
                     break;
         
                    // find the end of a sentence 
                   endIndex = buffer.IndexOf('\r', startIndex);

                    if (endIndex == -1)
                       break;
       
                      sentence = "";
         
                      sentence = buffer.Substring(startIndex, endIndex);

                      // if sentence wasn't recognize well, skip it and read new one
                      if (gpsInfo.Parse(sentence) == false)
                         break;
           
                      // Skip to next sentence in the buffer
                       i += sentence.Length;
                    }
                }
                catch (Exception ex)
                {
                    Debug.Print("Message: " + ex.Message);
                    Debug.Print("Stack Trace: " + ex.StackTrace);
                    Debug.GC(true);
                }

I though to replace the IndexOf() function with mine function, like that:

public static int FindChar(string buffer, char cToFind, int index, int len)
 {
            for (; index < len; index++)
            {
                if (buffer[index] == cToFind)
                    return index;
            }

            return -1;
        }
 }
     

But it didn’t help.
Beside this process I don’t do anything yet with the GPS info and I don’t know how can I continue if I get this exception all the time.
Can you advise?

Thanks

ami

The code you are showing wouldn’t use all memory! something else must be using the memory.
Check what assemblies you have added to your project and try to clean up the code.

This is the printing that I got before the exception:
GC: 1msec 31452 bytes used, 32928 bytes available
Type 0F (STRING ): 9516 bytes
Type 11 (CLASS ): 1896 bytes
Type 12 (VALUETYPE ): 72 bytes
Type 13 (SZARRAY ): 1404 bytes
Type 15 (FREEBLOCK ): 32928 bytes
Type 17 (ASSEMBLY ): 13668 bytes
Type 18 (WEAKCLASS ): 48 bytes
Type 1B (DELEGATE_HEAD ): 612 bytes
Type 1C (DELEGATELIST_HEAD ): 96 bytes
Type 1D (OBJECT_TO_EVENT ): 96 bytes
Type 1E (BINARY_BLOB_HEAD ): 360 bytes
Type 1F (THREAD ): 1152 bytes
Type 20 (SUBTHREAD ): 144 bytes
Type 21 (STACK_FRAME ): 1128 bytes
Type 27 (FINALIZER_HEAD ): 72 bytes
Type 31 (IO_PORT ): 72 bytes
Type 34 (APPDOMAIN_HEAD ): 72 bytes
Type 36 (APPDOMAIN_ASSEMBLY ): 1044 bytes
Failed allocation for 769 blocks, 9228 bytes

Regarding the assemblies, I think I reduced them to minimum.
I use:
System
System.IO
mscorlib
Microsoft.SPOT.Native
Microsoft.SPOT.Hardware
GHIElectronics.NETMF.System

Does Print.Debug use a lot of memory?
Is it possible that debugging with breakpoint can cause it also?

Thanks

ami
GHIElectronics.NETMF.USBHost

it is showing “32928 bytes available” so you have 33KB of free memory. This is plenty to do everything! Check the line that is causing the exception. Maybe it is trying to create some huge object that it shouldn’t…like a very large string.

OK I will
Thanks

Looks like buffer string will grow forever.

By the way, take a look at how we handle GPS in our driver.

Should

for (i = 0; i < len - 1; i++) 
           {
                buffer += array[i];
           }

be

for (i = 0; i < len - 1; i++) 
           {
                buffer += data[i];
           }

I think I found it


byte[] data = new byte[128];
char[] array;
string buffer = "";

while (true)
{ 
        len = serialUSB.Read(data, 0, ComBufferSize);
        array = System.Text.Encoding.UTF8.GetChars(data);

        // This line was missing - so the buffer get bigger and bigger
        buffer = "";
        for (i = 0; i < len - 1; i++)
        {
            buffer += array[i];
         }
}

BTW, is there a better way to convert byte[] to string?

Thanks for your help

ami

ami,

There’s a constructor for String that can simplify your code. The snippet below should work for you. Doing string concatenation using “buffer += …” should be avoided if possible, as this is an expensive operation even in the full .NET framework. Hope this helps.



byte[] data = new byte[128];
string buffer;

while (true)
{
    len = serialUSB.Read(data, 0, ComBufferSize);

    buffer = new string(
        System.Text.Encoding.UTF8.GetChars(data),
        0,
        len);
}


What about the “new”? It doesn’t spend memory without freeing it or the GC is take care of that?

Thanks

your += will make a “new” object in every single loop so you are making 1000 of objects already…that is because of how strings work

So one “new” is better of course.
Do I need to free it before the new loop or garbage collector will take care of it?

Thanks

Once you “new” up the string object in each loop, the GC will take care of the “old” string for you. There’s nothing else you need to do for cleanup. In full .NET and .NET Compact, we have the StringBuilder class to help us do efficient in-memory string manipulation, but that class hasn’t made it to MF. I’d recommend going to MSDN and reading about how System.Strings are handled in C#. Most of the info you find will be applicable to the Micro Framework.

Thanks a lot

Thanks Chuckie…

Adding on, to explain strings in few words. Strings are somewhat constant object. Once you create a string it can’t be modified. So you use += (concatenate strings) you are actually creating new string behind the scene.

string str1 = "FEZ";
string str2 = "Easy";

// this code will make a "new" string then leave old "FEZ" for garbage collection
str1 = str1+str2;