Click here to Skip to main content
15,886,518 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hello

I am trying to create a tile editor application that joins 16x16 sized png images into one large png file. I have tried this before when trying to develop other applications and have failed to get around the issue of memory leakage or just general GDI+ errors.

Now I know this isn't an issue with my computer as it's got 16GB RAM and 8 processors. So really this shouldn't be much of an issue for it.

I have read many posts surrounding disposal and Garbage Collection when dealing with bitmaps and graphics objects, but I seem to get conflicting answers wherever I go, some saying...
- You just need to dispose of the objects or use a Using. (Which I have done)
- Others say that although this is important, they don't actually do much in terms of memory issues. (Then what do I do to resolve this?)

My code:

VB.NET
Public Sub DisplayMap()

    Dim ArtFilePrefix As String = My.Settings.usr_ArtDumpFolder & "\" & "Tile_" & IO.Path.GetFileNameWithoutExtension(_FilePath) & "_"

    Using MapBmp As Bitmap = New Bitmap(_HeaderBlock.MapWidth * 16, _HeaderBlock.MapHeight * 16)
        Using MapGfx = Graphics.FromImage(MapBmp)

            For TileHeight As UShort = 0 To _HeaderBlock.MapHeight - 1
                For TileWide As UShort = 0 To _HeaderBlock.MapWidth - 1
                    With _MapBlock.MapCell(TileHeight * _HeaderBlock.MapWidth + TileWide)
                        MapGfx.DrawImage(
                            Bitmap.FromFile(ArtFilePrefix & _TextureRange(0).StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex) & ".png"),
                            New Rectangle(TileWide * 16, TileHeight * 16, 16, 16),
                            New Rectangle(0, 0, 16, 16),
                            GraphicsUnit.Pixel)
                    End With
                Next
            Next

            '\\Save the file and release the system resources.
            MapBmp.Save(My.Settings.usr_ArtDumpFolder & "\" & "Map_" & ".png", Drawing.Imaging.ImageFormat.Png)
        End Using
    End Using

End Sub


Description of the code:

Ok, so there are a few items in here that may not be obvious as to what they do so I've given some explanation as to what these are:

_HeaderBlock

A structure that contains general information, but for the purposes of this procedure determines how big the final image should be.

_MapBlock

A structure that contains information related to the specific 16x16 area that is being drawn in the final image.

_TextureBlock

Used to determine what 16x16 png file to obtain and to append to the final image.

What I have tried:

Putting the Using statements within the For Loops opposed to the outside to see if using the same objects multiple times caused it to break.

Putting in a GC.Collect at the end to see if I could force it to free up memory.

Saving the tiles to disk opposed to keeping them in memory (I have kept this in)
Posted
Updated 27-Mar-16 10:53am

1 solution

Quote:
Others say that although this is important, they don't actually do much in terms of memory issues.
When not using using-statements the CLR eventually comes around to cleaning up those objects but there's no guarantee on when this will happen. So it can lead to inconsistent behaviour. When using using-statements you're definitely on the safe side in this regard* but there can be other issues.

However, my first observation is that you don't actually use using-statements on all disposable objects which you create: The Bitmap.FromFile(..)-call creates a bitmap that you don't dispose of. I suggest changing it like this (within the With-statement):
VB
Using tileBmp As Bitmap = Bitmap.FromFile(ArtFilePrefix & _TextureRange(0).StartAddress + _TextureBlock.OffsetTextureTable(.TextureIndex) & ".png")
    MapGfx.DrawImage(tileBmp,
                     New Rectangle(TileWide * 16, TileHeight * 16, 16, 16),
                     New Rectangle(0, 0, 16, 16),
                     GraphicsUnit.Pixel)
End Using


Other than that: Do you compile your project for x86 architecture? Then the 16MB RAM of your PC don't help - the 32bit address space of a x86 process can't utilize that much and because of memory fragmentation the practical limit can be even lower than the theoretical one.

I'd suggest to first change your code as shown above. If the problem persists and you currently compile your project for x86, change it to x64.

* Edit: With using-statements you're on the safe side as in that the CLR will clean up those objects with the next garbage collection (not instantly, as my above wording might imply). Since garbage collections are not guaranteed to happen before your application tries to allocate an amount of memory that will lead to an OutOfMemory-exception it's still possible that one occurs but it's far less likely opposed to not using using-statements.
 
Share this answer
 
v2
Comments
Xenac 27-Mar-16 17:55pm    
Excellent, great solution and quick response too...

I don't want to tempt fate but I think you nailed it. I hadn't realised/noticed that that Bitmap object was being created each time.

I had to tweak it a little to get it to work, because it didn't like "As Bitmap.FromFile" to show "As Bitmap = "Bitmap.FromFile", and that seems to run without the memory leaks.

Many thanks to you Sascha
Sascha Lefèvre 27-Mar-16 18:08pm    
You're welcome! :-)
Sorry for the syntax mistake, VB.NET isn't my language of choice ;-)
I added a clarification to my answer above, please take a look.
cheers, Sascha

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900