Main Site Documentation

Speed/memory question about resources


#1

I was doing some bitmap loading, using some predefined bitmaps (resources)…this has led to an out of memory conditon…I do have a solution, but want to understand the problem & see if there is an alternate fix …note the large heap HAS been set:

        private static Bitmap tiled;
        public static void setupSplash()   //splash screen, first one shown
        {
            splash.Backcolor = Skewworks.NETClix.Colors.Blue;
            if (tiled==null) tiled = new Bitmap(800, 480);
            int i;
            int j;
            for (i = 0; i < 6; i++)
            {
                for (j = 0; j < 14;j++)
                {
                    tiled.DrawImage(i * 160, j * 34, Resources.GetBitmap(Resources.BitmapResources.Chevy), 0, 0, 160, 34);
                }
            }

            splash.BackgroundImage = tiled;

This is being called in a loop that should released it, but the memory goes down , down down, til an out of memory occurrs:

            int ppp = 0;
            while (true)
            {
                ppp++;
                Debug.Print(" splash scrn " + ppp);
                setupSplash();     //do it over & over to investigate memory issues
                splash.Dispose();
                Debug.GC(true);
            }
GC: 16msec 8749848 bytes used, 97080 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23256 bytes
Type 12 (VALUETYPE           ):    396 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ):  97080 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8673624 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   2124 bytes
Type 27 (FINALIZER_HEAD      ):  18744 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
Failed allocation for 912 blocks, 10944 bytes

    #### Exception System.OutOfMemoryException - CLR_E_OUT_OF_MEMORY (1) ####
    #### Message: 
    #### System.Resourc

instead of using resources.getbitmap…in the statement itself, I defined it as static ahead of time:

        static Bitmap testit = Resources.GetBitmap(Resources.BitmapResources.Chevy);
        private static Bitmap tiled;
        public static void setupSplash()   //splash screen, first one shown
        {
            splash.Backcolor = Skewworks.NETClix.Colors.Blue;
            if (tiled==null) tiled = new Bitmap(800, 480);
            int i;
            int j;
            for (i = 0; i < 6; i ++)
            {
                for (j = 0; j < 14; j++)
                {
                    tiled.DrawImage(i * 160, j * 34, testit, 0, 0, 160, 34);
                }
            }

MAN, what a speed difference! I could now barely read the debug screen flying by & the memory levels stay “steady” & never an error. …didn’t realize it would make a difference…but what about the original setup? WHY does it use more & more memory & can you prevent it with that edit, by somehow releasing the resource? Or is it just wise to make everything staitc as in the second method?


#2

It is not that you made your bitmap static but rather that your not generating it from Resources every time through the loop.

When you do:

               
 for (j = 0; j < 14;j++)
                {
                    tiled.DrawImage(i * 160, j * 34, Resources.GetBitmap(Resources.BitmapResources.Chevy), 0, 0, 160, 34);
                }

You are creating 14 new Bitmap objects. While the GC will ventually get rid of them you are using up all the memory before the GC has a chance. When you grab the bitmap ahead of time and just reference in the loop you are only generating the bitmap object once.

You could also do this:


        static Bitmap testit;
        private static Bitmap tiled;
        public static void setupSplash()   //splash screen, first one shown
        {
            testit = Resources.GetBitmap(Resources.BitmapResources.Chevy);
            splash.Backcolor = Skewworks.NETClix.Colors.Blue;
            if (tiled==null) tiled = new Bitmap(800, 480);
            int i;
            int j;
            for (i = 0; i < 6; i = i + 1)
            {
                for (j = 0; j < 14; j = j + 1)
                {
                    tiled.DrawImage(i * 160, j * 34, testit, 0, 0, 160, 34);
                }
            }

#3

It still seems strange, since this routine, setupSplash, can be called around 8 full times before the crash, and between the calls a debug.GC(true); is called, shouldn’t that be doing the trick? If not, what would do the trick (dump the no longer needed bitmaps)? I’m really just trying to get an understanding of how to get rid of things.

I’m surprised these are being “created”, or really “kept” once the drawimage method is done. Maybe its just how long they stick around.


#4

I’ve always thought (in simplistic terms) that the way the NETMF handles this is to tag the object as garbage when it goes out of scope or disposed, and let the GC get it when it next does it’s bit. And yes, I thought that if you explicitly did debug.gc(true) you should force GC to do it’s thing.

Out of interest, from a per-loop perspective, how much does the memory go up, and of what particular type, prior to getting the OOM ? I’m assuming binary_blob_head as it’s the huuuuge number, but does it go up per cycle in a number that makes sense based on your bitmap size?


#5

[quote]but does it go up per cycle in a number that makes sense based on your bitmap size?
[/quote]—Yes, it does, more or less

When I tried using the suggestion:

 private static Bitmap tiled;
        public static void setupSplash()   //splash screen, first one shown
        {
            testit = Resources.GetBitmap(Resources.BitmapResources.Chevy);

It was improved, but NOT as good as my original fix…the suggestion sloooowly ran out of memory & after around 772 splash screens ran dry & crashed…in this case the memory changed in smaller amounts. What is interesting, is adding in a thread.sleep(10) at the bottom of the calling while loop fixes it!! Can such a thing be fixed/forced without a sleep? note my original fix works fine without sleep (like me :wink: )

 splash scrn 771
GC: 17msec 8724840 bytes used, 122088 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23208 bytes
Type 12 (VALUETYPE           ):    372 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ): 122088 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8649636 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   1224 bytes
Type 27 (FINALIZER_HEAD      ):  18696 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
 splash scrn 772
GC: 17msec 8735832 bytes used, 111096 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23232 bytes
Type 12 (VALUETYPE           ):    372 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ): 111096 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8660580 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   1224 bytes
Type 27 (FINALIZER_HEAD      ):  18720 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
 splash scrn 773
GC: 17msec 8760792 bytes used, 86136 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23256 bytes
Type 12 (VALUETYPE           ):    396 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ):  86136 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8684568 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   2124 bytes
Type 27 (FINALIZER_HEAD      ):  18744 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
Failed allocation for 912 blocks, 10944 bytes

GC: 16msec 8760792 bytes used, 86136 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23256 bytes
Type 12 (VALUETYPE           ):    396 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ):  86136 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8684568 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   2124 bytes
Type 27 (FINALIZER_HEAD      ):  18744 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
Failed allocation for 912 blocks, 10944 bytes

GC: 16msec 8760840 bytes used, 86088 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23280 bytes
Type 12 (VALUETYPE           ):    396 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ):  86088 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8684568 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   2124 bytes
Type 27 (FINALIZER_HEAD      ):  18768 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
Failed allocation for 912 blocks, 10944 bytes

GC: 16msec 8760840 bytes used, 86088 bytes available
Type 0F (STRING              ):    276 bytes
Type 11 (CLASS               ):  23280 bytes
Type 12 (VALUETYPE           ):    396 bytes
Type 13 (SZARRAY             ):   1140 bytes
Type 15 (FREEBLOCK           ):  86088 bytes
Type 17 (ASSEMBLY            ):  25008 bytes
Type 18 (WEAKCLASS           ):     96 bytes
Type 19 (REFLECTION          ):    216 bytes
Type 1B (DELEGATE_HEAD       ):    432 bytes
Type 1D (OBJECT_TO_EVENT     ):    216 bytes
Type 1E (BINARY_BLOB_HEAD    ): 8684568 bytes
Type 1F (THREAD              ):   1152 bytes
Type 20 (SUBTHREAD           ):    144 bytes
Type 21 (STACK_FRAME         ):   2124 bytes
Type 27 (FINALIZER_HEAD      ):  18768 bytes
Type 31 (IO_PORT             ):    180 bytes
Type 34 (APPDOMAIN_HEAD      ):     72 bytes
Type 36 (APPDOMAIN_ASSEMBLY  ):   2772 bytes
Failed allocation for 912 blocks, 10944 bytes

    #### Exception System.OutOfMemoryException