LoadImage Bug

Archives Forums/BlitzMax Bug Reports/LoadImage Bug

TaskMaster(Posted 2009) [#1]
The LoadPixmap functions of the TPixMapLoaders have a memory leak.

I found this leak yesterday and thought it was something wrong in my program and it took me quite a while to trace it. But, it turns out that every time a TPixMapLoader fails to load an image, a small amount of memory is leaked. The funny thing about this bug is that depending on the order you import the loaders and what kind of image you are loading, you may not see the bug.

Basically, when you call LoadImage, BlitzMax attempts to load the image with each type of loader until it succeeds in finding one that worked or goes through them all. So, if you load a png and it is the first loader BlitzMax attempts to use, then you will not see any memory leaked. But, if you load a png and BlitzMax tries the bmp or jpg loaders first, then some memory is leaked.

The code follows. Here is what you can do to test it. When you run this code, BlitzMax will try the png loader first, since it was imported last, then it will try the bmp loader, then the jpg loader.

If you load a png, then no memory is leaked, if you load a jpg or bmp, then some memory is leaked. If you attempt to load a file that is not an image, then more memory is leaked, because all of the loaders will fail.

So, run the code as is, but replace the path to the image with a path to a file on your hard drive. if you load a png, no leak, if you load any other file, memory will be leaked.

Press L to load. And watch the memory usage in the task manager. The more you press L, the mor ememory is leaked. but, if the image is a png, no memory will be leaked at all. And each subsequent press of L will not use more memory.




GfK(Posted 2009) [#2]
I've tested this at length and I'm not 100% convinced. I'm using Blitzmax 1.34.

Firstly, I changed the code to the following, just to speed up the process - note the two underlined changes:
SuperStrict

Framework brl.max2d
Import brl.GLMax2D
Import brl.jpgloader
Import brl.bmploader
Import brl.pngloader

SetGraphicsDriver GLMax2DDriver()
Graphics(800, 600)

While Not AppTerminate()
	Cls
	If KeyDown(KEY_L)
		Local img:TImage
		For Local i:Int = 0 To 100
			img = LoadImage("image.jpg") '<-- Put your file path here.
		Next
	End If
	GCCollect()
	Flip
Wend

I *do* notice what appears to be a miniscule memory leak if I hold down the L key for several minutes. However, I get exactly the same behaviour even when I load a PNG image. Over a period of minutes the memory usage slowly crept up to just over 20MB.


Grisu(Posted 2009) [#3]
Can confirm the memory leak under Win7 RC1 (64 Bit) with bmx1.34 rc9.

Also, I have reported a similiar issue about 3 months ago: http://www.blitzbasic.com/Community/posts.php?topic=85013

Btw: You don't need the KeyDown-command nor the gfx stuff in the example.


TaskMaster(Posted 2009) [#4]
I am running the latest version of BlitzMax. The only reason I did it with a KeyHit is so you give the GC time to do its work and let the Task Manager settle down.

Yes, the leak is not that large, but it is a leak none the less. What proves it is that the memory usage does not climb if you load an image of the type that is the first PixMap loader, which in the case of this example is a png. If you load a bmp or non image file, it does leak memory.

if you really want to see it exacerbated, load a text file or something, not an image file. Then all of the loaders fail and the memory leak is larger.


TaskMaster(Posted 2009) [#5]
If you take out ALL of the framework and imports (so they all get loaded) and try to load a file that is not an image file, then the memory still leaks.

The size of the file makes no difference either. The file you try to load MUST exist though. If the file does not exist, then no memory leaks. My guess is that a file handle is being left open?!?!

SuperStrict

SetGraphicsDriver GLMax2DDriver()
Graphics(800, 600)

While Not AppTerminate()
	Cls
	If KeyDown(KEY_L)
		Local img:TImage
		For Local i:Int = 0 To 100
			img = LoadImage("textfile.txt") '<-- Put your file path here.
		Next
	End If
	GCCollect()
	Flip
Wend



Goober(Posted 2009) [#6]
has this been fixed in the past two months?

<sorry for the necro post>


Brucey(Posted 2009) [#7]
After much effort, I've tracked the jpgloader leak down, and have worked out a fix for it.

It all goes wrong in loadjpg() of loadjpeg.c

Some memory is allocated, but under two circumstances, it isn't freed.

The following code section is broken :
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo,(FILE*)stream);
	
	if( setjmp(jmp_env) ){return -1;}
	
	res=jpeg_read_header(&cinfo,TRUE);
	if (res!=1) return -1;

	jpeg_start_decompress(&cinfo);


and should be replaced with :
	jpeg_create_decompress(&cinfo);
	jpeg_stdio_src(&cinfo,(FILE*)stream);
	
	if( setjmp(jmp_env) ){
		jpeg_destroy_decompress(&cinfo);
		return -1;
	}
	
	res=jpeg_read_header(&cinfo,TRUE);
	if (res!=1) {
		jpeg_destroy_decompress(&cinfo);
		return -1;
	}

	jpeg_start_decompress(&cinfo);


This removes the leak for me.

Have fun

:o)


GfK(Posted 2009) [#8]
You should work for BRL. Or do you??

Anybody who knows: Can this fix be included in the next update?


TaskMaster(Posted 2009) [#9]
So the problem was only in the jpg loader?!?! Nice one Brucey, good job. Hopefully this will get added to the official source.


Brucey(Posted 2009) [#10]
So the problem was only in the jpg loader?!?!

Yep.
I've tested them all individually now (using Framework/Import), and I didn't see anything else (obviously) leaking.


marksibly(Posted 2009) [#11]
Hi,

Thanks again Brucey!


Goober(Posted 2010) [#12]
Thanks Brucey!

Hope to see this fix included in the next update :)


Grisu(Posted 2010) [#13]
Could someone please check the PNG Loader as well?

I'm getting a leak with this one too... :(


Corum(Posted 2010) [#14]
Good job, Brucie! :-)

Edit:
Oops.. it's a bug solved 1 month ago.
I drunk too much tonight. :P