Rare behavior?

BlitzMax Forums/BlitzMax Programming/Rare behavior?

orgos(Posted 2010) [#1]
Hi

I don't sure where to post this message, here or in bug section, so I decide to put it here.

I have this code:

SuperStrict

SetGraphicsDriver D3D9Max2DDriver()
Graphics 800,600

Global fullScreen:Int = False

Global img:TImage = LoadImage("test.png")

Global list:TList = New TList

Type entity
	Field x:Float
	Field y:Float
	Field _link:TLink
End Type

For Local i:Int = 1 To 400
	Local e:entity = New entity
	e.x = Rand(1, 800)
	e.y = Rand(1, 600)
	e._link = list.addlast(e)
Next

While 1
	Cls
	
	For Local e:entity = EachIn list
		DrawImage(img, e.x, e.y)
	Next
	
	If (KeyDown(KEY_SPACE))
		For Local e:entity = EachIn list
			e._link.remove()
			e = Null
		Next
		list = New TList
		GCCollect()
	End If

	
	If (KeyDown(KEY_ESCAPE))
		End
	End If
	
	If (KeyDown(KEY_LALT) And KeyDown(KEY_ENTER))
		If (fullScreen = True)
			Graphics 800,600
			fullScreen = False
		Else
			Graphics 800,600, 32
			fullScreen = True
		End If
	End If
	
	Flip
Wend



Note: test.png is any png image with 32x32px

Here I have two situation

First:

I create 400 images, and put it on a Tlist, then draw all the images in Tlist, so when I press space all the images must be erased.

I see the RAM occupied by the executable using window Task Manager and then press space, and I no see the memory goes down, indeed the memory rise up a bit.

Is some thing wrong or this behavior is normal?

Second:

On windows 7 using directx9 graphic driver when I press the Alt+Enter keys combination the program change from windows mode to full screen without problem but the memory goes up considerably and that happen each time I change the resolution.

This not happen if I use directx7 graphic driver.

I'm doing wrong the change screen procedure?

All the test are in release mode.

I'm using the last BMax version.

Thanks.


Leon Drake(Posted 2010) [#2]
hmm usually i don't go as far as using the OOP commands for working with lists, i'm quite satisfied using Clearlist and listremove.

but i just tried your code and noticed there is a tiny increase in memory after removing all the types from the list.


Dabhand(Posted 2010) [#3]
This looks fine to me and seems like the garbage collector is grafting as it should.

I've changed it a little, press A to set everything up, then Space to clear the lot, or keep on hitting A then Space (Or even just hit A repeatedly) and you'll see (well here it does) the memory moves a bit, but after a few goes it calms down to a steady fluctuation, with no apparent 'leak', which would be more worrying, but alas, all seems rosey:-

SuperStrict

SetGraphicsDriver D3D9Max2DDriver()
Graphics 800,600

Global fullScreen:Int = False

Global img:TImage

Global list:TList = New TList

Type entity
	Field x:Float
	Field y:Float
	Field _link:TLink
End Type



While 1
	Cls
	
	If img <> Null
		For Local e:entity = EachIn list
			DrawImage(img, e.x, e.y)
		Next
	End If
	
	If KeyHit(KEY_A)
		For Local e:entity = EachIn list
			e._link.remove()
			e = Null
		Next
		img = Null
		list = New TList
		GCCollect()
		
		For Local i:Int = 1 To 400
			Local e:entity = New entity
			e.x = Rand(1, 800)
			e.y = Rand(1, 600)
			e._link = list.addlast(e)
		Next
		img = LoadImage("D:\backup\Blitz\NagsDarts_RC1_0\Media\gfx\180.png")
	End If
	
	If (KeyDown(KEY_SPACE))
		For Local e:entity = EachIn list
			e._link.remove()
			e = Null
		Next
		list = New TList
		img = Null
		GCCollect()
	End If

	
	If (KeyDown(KEY_ESCAPE))
		End
	End If
	
	If (KeyDown(KEY_LALT) And KeyDown(KEY_ENTER))
		If (fullScreen = True)
			Graphics 800,600
			fullScreen = False
		Else
			Graphics 800,600, 32
			fullScreen = True
		End If
	End If
	
	Flip
Wend


Thing is you've got to remember that the GC sometimes doesnt instantly clear the resources, so you'll probably witness memory building up then snapping back down to a steady rate.

Dabz


orgos(Posted 2010) [#4]
@Dabhand(givesup)

I think the problem is not to free the resource var, but the memory size of 400 created entities.

I monitor the memory of the program for 10 minuts after make the entity delete procedure and the memory never goes down from original size.


Arowx(Posted 2010) [#5]
The GC could be allocating blocks of memory and retaining them?

Does the memory stay constant even when re-allocating more objects, as this could indicate the GC is reusing previously allocated memory?


ima747(Posted 2010) [#6]
I'm noticing a retention problem in my project as well. I haven't touched the areas concerned in a while (maybe a month...), but I have been updating bmax. I noticed 2 days ago that my threaded loading routine doesn't properly garbage collect any more. If I call GCCollect() it frees properly, but auto collecting doesn't clean up, my memory builds and builds until it locks up. This is on Mac btw. I've tried rolling some modules back but it takes so long to re-compile everything on my system that I just don't have time to roll and recompile a million versions to try to figure out where/when this started. Further I know the objects are being removed (I put a print in their delete emthod) and that by extension they are calling delete on their memory blocks... it just hangs around. It does go up and down a little indicating that SOME collection is occuring but without a manual call to GCCollect() it will build and build...


ima747(Posted 2010) [#7]
Taking another look into the GC it seems for me atleast on mac that the alloc size test is failing in the auto collect routine

(gc_alloced-alloced)>heap_size/3

line 207 in blitz_gc_ms.c


Arowx(Posted 2010) [#8]
Looking into a bug/delay in my latest game, it records data as the game progresses and then uses the data to show the user graphs at the end of each turn, it uses a very simple timestamp object to record a value of a parameter in a list.

Now in theory the game (Save The Silly Earthlings [Alpha]) could end up storing 30 pieces of info for every hour in 100 years (or about 26,298,000 elements).

Anyway though the slowdown could be caused by the current Alpha version clearing out 5 years worth of data (about 5m elements).

Stress testing that now and it would appear that the game in single threaded mode is not GC'ing the cleared data, just using a simple Nulling of the lists at the moment?

Windows Vista Ultimate 64bit!


ima747(Posted 2010) [#9]
SuperStrict

While(Not AppTerminate())
	Delay(10)
	Local pixm:TPixmap = LoadPixmap("sample2.png")
wend


give that a large (multi-meg) png or jpeg to load and watch memory usage... in threaded or non threaded compile I watch the memory go up up up, it goes down tiny bits here and there but generally it's steadily climbing. since the pixmap is local it's getting released every loop... if I use a small png or jpeg (under 100kb) it will climb to between 11 and 54mb before clearing back down, which is the normal cycle for the GC... I don't know what it means but it explains why I'm getting climbing to death in my project since I'm mainly working with large pictures.

IMPORTANT note, if you use FreeImage, which overrides the loadpixmap (or if you load image instead of using loadpixmap), OR if you load freeimage objects instead of strait pixmaps you get the same behavior, so it isn't loadpixmap per-se.

Can anyone else confirm they see the same climbing of memory as me? have only tested on my mac so far. [update] same results under windows for me, just grows and grows.

also loading on child threads at the same time causes all kinds of havok, here's a sample to play around with, just toggle some comments on and off to see how it goes wrong. loading JUST in a child thread just causes the same memory climb though.

SuperStrict

'Import bah.freeimage


Function tload:Object(in:Object)
	While(True)
		Local pixm:TPixmap = LoadPixmap("sample2.jpg")
		Delay(10)
	Wend
End Function



'CreateThread(tload, "")

While(Not AppTerminate())
	Delay(10)
	Local pixm:TPixmap = LoadPixmap("sample2.png")
	'Local image:TImage = LoadImage("sample2.jpg")
wend



Arowx(Posted 2010) [#10]
Wierd behaviour here,

Build 30 lists of 5*24*365 data objects containing an int and float,

Release build single threaded (ST)...

Creates the 30 lists filling with random values in 465 ms.

* Clearing the 30 lists using list[i].Clear() takes 3695 ms

* for the first pass, subsequent passes take about 200 ms?

Ditto for debug (ST), the first clearing takes 10+ times longer?

Odd no?


Arowx(Posted 2010) [#11]
It appears to be faster in this test case using Multi-threading (MT) and the first clearing pass is as fast as all subsiquent passes?


Dabhand(Posted 2010) [#12]

Can anyone else confirm they see the same climbing of memory as me? have only tested on my mac so far. [update] same results under windows for me, just grows and grows.



Does the memory build, spike, then drop off, and I mean, take a load before it dumps and simmers at a decent (expectant) level?

Dabz


Dabhand(Posted 2010) [#13]
Further reading:-

http://www.blitzbasic.com/Community/posts.php?topic=89969#1023084

Which in laymens terms mean, if your app goes should rocket memory, crash your OS, or run it to a crawl then yep, theres something wrong.

If you can chaps, stress your apps and keep an eye on memory.

Dabz


Dabhand(Posted 2010) [#14]
P.S. systems specs go a long way to! ;)

Dabz


ima747(Posted 2010) [#15]
Re dab: with a small picture it builds and then falls in a normal cycle (as apps in the past always have) with a large picture I think it tried but the peak before it would drop and reset seems too high... So it just builds till it runs out of ram and crashes.


Dabhand(Posted 2010) [#16]

Re dab: with a small picture it builds and then falls in a normal cycle (as apps in the past always have) with a large picture I think it tried but the peak before it would drop and reset seems too high... So it just builds till it runs out of ram and crashes.



How large is the picture, can you post it?

Dabz


ima747(Posted 2010) [#17]
5.8mb sample2.jpg

It's important to note though that this happens with any large picture, on mac, or PC, with or without using freeimage. This means it's not the file (any picture) it's not the OS (mac/win) and it's not the loading/unloading mechanism (freeimage/standard).

This only leaves the garbage collector not auto collecting properly, which can be demonstrated by doing a manual GCCollect(), this causes the memory to stay low. So the collector CAN collect it. I suspect it would auto collect it eventually but it allows it to rise to a point that it crashes before it tries to collect (this is based on comparing the behavior of a small picture to a large picture)


Derron(Posted 2010) [#18]
cpu time: 14 seconds, memory usage ~700mb.

It is independend of the usage of "globals" or locals...nulling is useless too.

Watching my system monitor, it shows a memory usage decrease for one time...after 7-8 seconds, afterwards the memory climbs until even swap file is excessively used. This just happens if the picture is a bit smaller (width 1280, your example rotated clockwise by 90°) but doesn't happen every run. The larger picture has a linear increase of memory over time ... so NO garbage is collected.

Compiled under ubuntu lucid, bm 1.36 and up


edit: just resaved the jpg as tga and voila... gc seems to work again, so i think it has to do something with the image loader not the collector.

bye MB


ima747(Posted 2010) [#19]
I've tried it with png with the same result. Also note that if you force a garbage collect it doesn't climb forever... it's that the auto collect isn't getting triggered. I put a printf in the auto collect to watch it and it doesn't get called due to a failed test (see above regarding line 207), if you comment out the test so it always auto collects it won't climb. (again because it's always collecting).

And again to note, this happens if you use freeimage as well, which replaces the standard load routines with it's own...

interesting that you're getting different results with a TGA however...

how does a small TGA compare to a small JPEG? do they both cycle the same, or does the JPEG have a larger swing in it's collect cycle?


ima747(Posted 2010) [#20]
Maybe this is related

http://www.blitzbasic.com/Community/posts.php?topic=91360

Looks like a leak but followup looks like it stabilizes after enough iterations...


Derron(Posted 2010) [#21]
I have had let the code above run for about 30 seconds... after that i had my ram 100% used, swap getting bigger and bigger.

Using TGA-Files the GC seemed to work flawlessy, no rising memorycurve in sys monitor.

PNG and Jpeg are both highly compressing the images, tga is using a kind of lzha/zip mechanisms.

bye MB