Main Site Documentation

Garbage Colection and memory Issues with STACK_FRAME GC


#1

Hi All,

I have incrementally been adding code to my FEZ Cobra project and all of a sudden hit some limit so the program won’t run/deploy properly:

I am not loading heaps of large images, (in total 6 x 480x272 kbd images 100KB each, and 5x2KB file) (i.e. at most resources have 1MB of resources), my main concern is to know what the 12MB of “STACK_FRAME” is being used for. I’m not using multi dimensional arrays either.

I am though using most reference GHI.Hardware DLL’s for GHI GHI.Glide and Microsoft.SPOT

GC gets activates as soon as program starts

Do Static variables get stored in the same memory space as dynamically allocated variables? My program worked find - no changes, when everything was dynamic, but now I’ve made some items static I get the problem below:-


Type 0F (STRING              ):   2676 bytes
Type 11 (CLASS               ):   7476 bytes
Type 12 (VALUETYPE           ):   3684 bytes
Type 13 (SZARRAY             ):   8328 bytes
Type 15 (FREEBLOCK           ):  79104 bytes
Type 16 (CACHEDBLOCK         ):     72 bytes
Type 17 (ASSEMBLY            ):  41976 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    192 bytes
Type 1B (DELEGATE_HEAD       ):    612 bytes
Type 1D (OBJECT_TO_EVENT     ):     72 bytes
Type 1E (BINARY_BLOB_HEAD    ): 952188 bytes
Type 1F (THREAD              ):    384 bytes
Type 20 (SUBTHREAD           ):     48 bytes
Type 21 (STACK_FRAME         ): 12528252 bytes <<<<<<<<<<<<<<<<<<<<<<<
Type 22 (TIMER_HEAD          ):     72 bytes
Type 27 (FINALIZER_HEAD      ):    288 bytes
Type 31 (IO_PORT             ):     72 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   5172 bytes
GC: 2335msec 13621020 bytes used, 9816 bytes available

Any Ideas Why?


#2

Why not load what you need dynamically at run-time and then dispose when you are done with it?


#3

Hi Gus,

OK, but what is causing STACK_FRAME to be at 12MB?

Problem is its a GSM, GPS tracking and GUI appl, so need most assemblies all the time.

Is there a working example out there on how to do what your talking about?

Thanks for quick reply been stuck a couple of days on this. and is killing the project.


#4

I am not sure as I never seen it before. You may get better answer on this from Microsoft directly? www.netmf.com


#5

Is there an example on how to dynamically load unload assemblies?


#6

You shouldn’t need to do that! I can’t see how your assemblies are 12MB! That would be few millions of lines of code :slight_smile:


#7

The core structure of my appl is:

4 threads: GUI, IO, M2M, APPL_LOGIC

And they are not using alot of memory either!

Is there a an easy way in C# to do sizeof() as in C++? then I might be able to narrow it down to an offending object.


#8

I am personally not sure.


#9

There is a c# sizeof keyword but it only works on value types so I don’t think that’ll help you. You can try calling Debug.GC(true) on a timer or at interesting events and that’ll force the GC to run - maybe the output from that will help narrow down when the problem occurs.

Do any of those threads you’re using start and stop or are they running all the time? Starting a new thread can consume a lot of stack space (in full .net anyway) so if you’re leaking threads, you can quickly end up with a big stack frame bucket…


#10

I have only 4 Threads,
I’ve disabled my Thread watchdog from doing any restarts whilst debugging / developing.
Thanks for tips.


#11

I’m just going to blog findings as they come in…

I’m forcing GC Garbage Collection to occur which spits out memory usage into the Debug output window

  
public static void Main()
        {
            try
            {
                Debug.EnableGCMessages(true);
                Debug.GC(true);
                long l = new long(); //<<< Example of instantiation - to work out size of object.
                Debug.GC(true);


                if (Init())                   //Start all Threads
                {
                    while (mbContinue)
                    {
                        //restart tasks that may have died
                        Watchdog();

                        //allow other threads for HW, GUI, APPL, M2M to run 
                        Thread.Sleep(5000);
                    }
                    Shutdown();
                    Debug.EnableGCMessages(false);
                }
            }
            catch (Exception Ex)
            {
                   ...
            }

        }

At start of application BEFORE any code runs:

GC: 10msec 1026600 bytes used, 12604236 bytes available
Type 0F (STRING              ):   2580 bytes
Type 11 (CLASS               ):   5700 bytes
Type 12 (VALUETYPE           ):   3684 bytes
Type 13 (SZARRAY             ):   7896 bytes
Type 15 (FREEBLOCK           ): 12604236 bytes
Type 16 (CACHEDBLOCK         ):     72 bytes
Type 17 (ASSEMBLY            ):  42012 bytes
Type 18 (WEAKCLASS           ):     48 bytes
Type 19 (REFLECTION          ):    192 bytes
Type 1B (DELEGATE_HEAD       ):    612 bytes
Type 1D (OBJECT_TO_EVENT     ):     72 bytes
Type 1E (BINARY_BLOB_HEAD    ): 957492 bytes
Type 1F (THREAD              ):    384 bytes
Type 20 (SUBTHREAD           ):     48 bytes
Type 21 (STACK_FRAME         ):    408 bytes
Type 22 (TIMER_HEAD          ):     72 bytes
Type 27 (FINALIZER_HEAD      ):    288 bytes
Type 31 (IO_PORT             ):     72 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   4896 bytes


#12

Solved:

solution:
i) More sleep and less frantic midnight coding, under pressure
ii) Init() function inside a thread was calling itself! only became apparent by putting loads of Debug.GC(true) after each instantiation. :slight_smile:


public void Init()
{
         Init();  ///// Causes STACK_FRAME memory allocation to explode!
         .......
}



#13

That’ll definitely eat your whole stack!

Glad you sorted it. :slight_smile: