Main Site Documentation

G120 freezing on garbage collection


#1

Hi,

I have an application (NETMF 4.3) running on a G120 that is always freezing on the second execution of the garbage collector, either when forced to run or when left to run when it chooses. The garbage collector executes after ~7 minutes, so the application can run without error for ~14 minutes before freezing when the garbage collector executes for the second time, then the device will stay frozen and must be restarted.

The code is too big to post here, and in any case would not run without the exact connected hardware, so I’m wondering if anyone has any experience with something similar that they can share to point me in the right direction? What are the possible scenarios where the garbage collector causes the device to freeze? As the application runs for a period of time without error how can I track down the offending piece of code?

Below is an example of the debug output from each garbage collector execution before the device freezes.

Thanks in advance.

[quote] GC: 105msec 404208 bytes used, 6935460 bytes available
Type 0F (STRING ): 1728 bytes
Type 11 (CLASS ): 8388 bytes
Type 12 (VALUETYPE ): 144 bytes
Type 13 (SZARRAY ): 3768 bytes
Type 03 (U1 ): 1596 bytes
Type 04 (CHAR ): 492 bytes
Type 07 (I4 ): 60 bytes
Type 0C (R8 ): 144 bytes
Type 0F (STRING ): 168 bytes
Type 11 (CLASS ): 1308 bytes
Type 15 (FREEBLOCK ): 6935460 bytes
Type 16 (CACHEDBLOCK ): 384 bytes
Type 17 (ASSEMBLY ): 28248 bytes
Type 18 (WEAKCLASS ): 48 bytes
Type 19 (REFLECTION ): 168 bytes
Type 1B (DELEGATE_HEAD ): 432 bytes
Type 1D (OBJECT_TO_EVENT ): 408 bytes
Type 1E (BINARY_BLOB_HEAD ): 352212 bytes
Type 1F (THREAD ): 1152 bytes
Type 20 (SUBTHREAD ): 144 bytes
Type 21 (STACK_FRAME ): 1152 bytes
Type 27 (FINALIZER_HEAD ): 624 bytes
Type 31 (IO_PORT ): 612 bytes
Type 34 (APPDOMAIN_HEAD ): 72 bytes
Type 36 (APPDOMAIN_ASSEMBLY ): 4524 bytes
GC: 106msec 403488 bytes used, 6936180 bytes available
Type 0F (STRING ): 1728 bytes
Type 11 (CLASS ): 8148 bytes
Type 12 (VALUETYPE ): 144 bytes
Type 13 (SZARRAY ): 3720 bytes
Type 03 (U1 ): 1572 bytes
Type 04 (CHAR ): 492 bytes
Type 07 (I4 ): 36 bytes
Type 0C (R8 ): 144 bytes
Type 0F (STRING ): 168 bytes
Type 11 (CLASS ): 1308 bytes
Type 15 (FREEBLOCK ): 6936180 bytes
Type 16 (CACHEDBLOCK ): 48 bytes
Type 17 (ASSEMBLY ): 28248 bytes
Type 18 (WEAKCLASS ): 48 bytes
Type 19 (REFLECTION ): 168 bytes
Type 1B (DELEGATE_HEAD ): 432 bytes
Type 1D (OBJECT_TO_EVENT ): 408 bytes
Type 1E (BINARY_BLOB_HEAD ): 352248 bytes
Type 1F (THREAD ): 1536 bytes
Type 20 (SUBTHREAD ): 192 bytes
Type 21 (STACK_FRAME ): 612 bytes
Type 27 (FINALIZER_HEAD ): 600 bytes
Type 31 (IO_PORT ): 612 bytes
Type 34 (APPDOMAIN_HEAD ): 72 bytes
Type 36 (APPDOMAIN_ASSEMBLY ): 4524 bytes
[/quote]


#2

Freezing would indicate that one of your threads has possibly gone into an endless loop.

How many threads do you have?

What happens when you press BREAK, does it respond?


#3

I would guess that if you see the debug Output from GC, that the GC was completed and successfull.
I think it might be possible that some object you have created might be freed by GC and thats why your app might Crash.
Every object you create must be referenced by your Code from some where.
There is one exception tho: Thread objects are referenced by the Framework itself until the thread has exited.


#4

Many thanks for the input.

I found the offending code. I was setting up a serial port object and then creating it again with a different baud rate. I somehow missed the fact you can change the baud rate property without having to set up the serial port object again. :-[

I’m still not 100% sure why the GC scooped it up but here’s the code that caused it;


        public GPS(string portName, int baudRate, Cpu.Pin LED)
        {
            // Set MTK3339 baud to 19200
            MTK3339 = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
            // Set up the GPS module
            MTK3339.ReadTimeout = 0;
            MTK3339.Open();
            // Set baud rate to 19200
            data_send = Encoding.UTF8.GetBytes("$PMTK251,19200*22" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
            // Close UART port
            MTK3339.Close();

            Thread.Sleep(200); // give the GPS module time to think about it!

            // use an LED to indicate successful comms with the GPS module
            LED_RX = new OutputPort(LED, false);

            // Set up the serial port for 19200 baud
            MTK3339 = new SerialPort(portName, 19200, Parity.None, 8, StopBits.One); //19200 baud = 0.5ms per byte
            MTK3339.ReadTimeout = 0;
            MTK3339.Open();
            MTK3339.DataReceived += new SerialDataReceivedEventHandler(MTK3339_DataReceived);
            // Set NMEA sentences to GPRMC only
            data_send = Encoding.UTF8.GetBytes("$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
            // Set update rate to 10hz this is also our logging rate for all data
            data_send = Encoding.UTF8.GetBytes("$PMTK220,100*2F" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
        }

And the working code;


        public GPS(string portName, int baudRate, Cpu.Pin LED)
        {
            // Set MTK3339 baud to 19200
            MTK3339 = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
            // Set up the GPS module
            MTK3339.ReadTimeout = 0;
            MTK3339.Open();
            // Set baud rate to 19200
            data_send = Encoding.UTF8.GetBytes("$PMTK251,19200*22" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
            // Close UART port
            MTK3339.Close();

            Thread.Sleep(200); // give the GPS module time to think about it!

            // use an LED to indicate successful comms with the GPS module
            LED_RX = new OutputPort(LED, false);

            // Set up the serial port for 19200 baud
            MTK3339.BaudRate = 19200; //19200 baud = 0.5ms per byte
            MTK3339.Open();
            MTK3339.DataReceived += new SerialDataReceivedEventHandler(MTK3339_DataReceived);
            // Set NMEA sentences to GPRMC only
            data_send = Encoding.UTF8.GetBytes("$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
            // Set update rate to 10hz this is also our logging rate for all data
            data_send = Encoding.UTF8.GetBytes("$PMTK220,100*2F" + "\r\n");
            MTK3339.Write(data_send, 0, data_send.Length);
        }

#5

Hi wolfbuddy,

Hopefully I’ve interpreted this correctly, and I’m not trying to teach you to “suck eggs”, but in your “bad” code, you have:

    
    MTK3339 = new SerialPort(portName, 9600, Parity.None, 8, StopBits.One);
    ...
MTK3339 = new SerialPort(portName, 19200, Parity.None, 8, StopBits.One); //19200 baud = 0.5ms per byte


As such, when the garbage collector runs, the first “SerialPort” (the 9600 one) gets removed, which is causing your errant behaviour.

I presume this is because SerialPort::Close doesn’t actually close things completely, so something inside of your program (or the NETMF runtime, potentially) gets confused when the old serial port gets GC’d.

Cheers,

Andrew