Image not freed?

BlitzMax Forums/BlitzMax Beginners Area/Image not freed?

Jeroen(Posted 2004) [#1]
I'm busy learning BlitzMax (Mark, damn, it rules!) and I was wondering where all the commands like FreeImage are gone. I guess "release" does the same? If so, why is the handle to the image released, and not the actual memory it uses?

Please try the example below. (I have blitzMax on M:\ so you have to change it in C:\ or something else)

Strict
Graphics 800,600,0

Type Oink

     Field x%
	Field y%
	Field image

	
	Function Create:Oink(a$)
		' The constructor refers to object Oink (After the ':") and asks for a string as argument.
		' A function does not know anything about where it is, unlike the method, so we must do this.
		Print "At start, mem: "+MemAlloced()
		Local o:Oink = New Oink
		Local x, y, image
		o.x = x
		o.y = y
		o.x = 100
		o.y = 200
		o.image = image
		o.image = LoadImage ("M:\Blitzmax\samples\birdie\games\platformgame\media\tiles\block1.PNG")
		Print "Object created, image loaded, mem: "+MemAlloced()
		Return o
	End Function

	Method Destroy ()
		' Be gone, thou evil object!
		Release image
		FlushMem
		Print "Object removed, mem: "+MemAlloced()
		
	End Method
	
End Type

' ---------------------------------------------------------------------------------------------

Local o:Oink = Oink.Create("HAHA!")
o.Destroy()
End




Note to Mark: a lot of commands can use some additional descriptions. In Blitz you used to 1. explain what it does (like now), 2. give a more human description of what it does "chit-chat", and 3. an example. Well, I miss (2) for some commands :-)


Perturbatio(Posted 2004) [#2]
At start, mem: 84241
Object created, image loaded, mem: 7241544
Object removed, mem: 7241712


Jeroen(Posted 2004) [#3]
Euh, thanks Perturbatio. I wasn't clear enough with my question:

Why is the memory not back at 84241, or close to that value?


Perturbatio(Posted 2004) [#4]
at a guess, it's because you are testing the free mem before the type has been instantiated as well, but when you show mem after the image is removed, the type itself still exists.


Jeroen(Posted 2004) [#5]
Hmmm okay, I wanted to delete the object
From the method Destroy, but ofcourse that is not possible. I would need a function (I don't know if that is possible as well, I guess so).

Correct code, which ends up with even less (?) memory than at start:

Strict
Graphics 800,600,0


' methods werken alleen met bestaande objecten
' je kan Method New gebruiken om object met b:blah = new blah() aan te maken,
' maar een constructor is uitgebreider, omdat je argumenten kunt gebruiken.
' je maakt dan een object aan met o:blah = blah.MaakAan("BLAH")

Type Oink

     Field x%
	Field y%
	Field image

	
	Function Create:Oink(a$)
		' The constructor refers to object Oink (After the ':") and asks for a string as argument.
		' A function does not know anything about where it is, unlike the method, so we must do this.
		Local o:Oink = New Oink
		Local x, y, image
		o.x = x
		o.y = y
		o.x = 100
		o.y = 200
		o.image = image
		o.image = LoadImage ("M:\Blitzmax\samples\birdie\games\platformgame\media\tiles\block1.PNG")
		Return o
	End Function

	Method DestroyMedia ()
		' Be gone, thou evil object!
		Release image	
	End Method
	
End Type

' ---------------------------------------------------------------------------------------------

Print "At start, mem: "+MemAlloced()
Local o:Oink = Oink.Create("HAHA!")
o.DestroyMedia()
Release o
FlushMem
Print "Object removed, mem: "+MemAlloced()

End



Perturbatio(Posted 2004) [#6]
yeah, I just did a test similar to that and got the same results. It's a little perplexing.

What does concern me is that when you do MemAlloced() at the start, I get 84241, once the image is loaded, it returns 7241651 which is two digits longer than before.


Perturbatio(Posted 2004) [#7]
not a solution to the memory issues, but a Destroy function:



Jeroen(Posted 2004) [#8]
Perhaps Blitzmax uses some memory to build up some stuff, to initialize stuff that can be removed safely with FlushMem?
Dunno, just an idea :)

Now, I want to be able to free my object with the "constructor" principle (I'd better call it "destructor" then). How can I remove the image and the object itself using a function inside an object?

Thanks,

Jeroen


Perturbatio(Posted 2004) [#9]
 ^
/|\
 |
 |



Jeroen(Posted 2004) [#10]
Heh, heh I didn't see that codebox before!

Thank you.


FlameDuck(Posted 2004) [#11]
I'm busy learning BlitzMax (Mark, damn, it rules!) and I was wondering where all the commands like FreeImage are gone.
They are pointless now.

I guess "release" does the same?
No. Release is a command that specifies that you're done with an integer reference to an object. FlushMem is the command that actually frees up memory. Witness:
So the answer to the question "How do you free images in BlitzMAX?" is "You don't, BlitzMAX and it's pseudo garbage collector does it for you!".


Jeroen(Posted 2004) [#12]
Hmmmmm, I'm very B3D oriented, so some things are confusing to me. I have some questions on your code snippet, FlameDuck:

Field image:TImage

What is TImage exactly, why not just 'image'?

And secondly, does the garbage collector only work when I use A "Tlist"?


marksibly(Posted 2004) [#13]
Hi,

'TImage' is a Type - its returned by LoadImage and used by DrawImage etc.

Basically, this means there are 2 ways to refer to images. The classic way...

Local image=LoadImage( "Blah" ) 'nice 'n' friendly...

...and the 'new' way...

Local image:TImage=LoadImage( "Blah" ) 'bit more verbose...

If you use the classic way, you must later release the image using 'Release'...

Release image

...and you can think of Release as the equivalent of FreeImage, FreeSound, FreeWhatever.

If you use the new way, it's (almost) all handled for you: the image will be deleted the next time 'FlushMem' is called and it's no longer in use.

And all this has nothing to do with lists!


Jeroen(Posted 2004) [#14]
Thanks!

....But, still not entirely clear to me.

I understand the "classic way". Release is the equivalent of all "free" commands. Handy.

But, the "new way" seems unclear to me; how does the garbage collector know something is used or not? In your example, you make a "Blah" image, and then later on you say "flushMem". But, if I don't delete anything manually, how can the garbage collector know what is obsolete or not?

As you say, "the image will be deleted the next time 'FlushMem' is called". But why does it do that? I never told Blitz that the object is obsolete. Is the garbage collector looking at which objects are in a Tlist and not?

Hmmm, I hope you understand what I'm trying to tell :)


FlameDuck(Posted 2004) [#15]
But, the "new way" seems unclear to me; how does the garbage collector know something is used or not?
Because it counts how many types you've made. Once you don't have anything left that references the data in question (and thus no way to access it) the garbage collector releases it's resources.

But, if I don't delete anything manually, how can the garbage collector know what is obsolete or not?
It can't know when you're done using it (what I assume you mean when you say obsolete). But what it can tell is when you couldn't possibly use it anymore, even if you wanted to, at least as long as you're using types, and not the "classic way".

As you say, "the image will be deleted the next time 'FlushMem' is called". But why does it do that? I never told Blitz that the object is obsolete.
You don't have to. It counts how many objects you have in play, and when that count reaches zero, it goes "poof".

What is TImage exactly, why not just 'image'?
Because BlitzMAXs types all (?) use "Hungarian Notation". Now hungarian notation is a discipline where by you prefix (typically) a letter to the actual variable name or reference. For instance a float that stores the X position of something could be called fXPosition. In Blitz3D the hungarian notation for this would be XPosition# (if you used it religiously).

Hungarian Notation is a mnemonic technique used to indentify what kind of references you're currently working with, and provides a way to distinguish myPlayer - the object, from myPlayer - the number.

And secondly, does the garbage collector only work when I use A "Tlist"?
No. The TList is just collector type (note the leading T), that makes juggling objects around much easier. They function similarilly to the way Types used to work in the "Classic way", except now you can have more of them for each type (you could have a list of aliens for each level, and so on, allowing much more advanced object hierarchies than what was possible using Blitz3D), the downside being you have to add them all manually.


Jeroen(Posted 2004) [#16]
Thanks Mikkel.

Please tell if I'm right with my conclusion,
based on Mark's and Mikkel's answers:

------------------------------------------------------
OLD WAY:
When I load a JPG or whatever media like this:
Local image=LoadImage( "Blah.jpg" )

... The *object* TIimage is *not* returned, just a reference
to the image. This is why you will need to release the image
manually and the garbage collector doesn't know anything
'bout it.

------------------------------------------------------
NEW WAY:

In order to do this, I will need to load stuff like this:
Local image:TImage=LoadImage( "Blah.jpg" )

...Where TIimage is the type/object that LoadImage returns.
This is how the garbage collector can keep track of it's
existance as an object.

When I 'release object', I release the reference. When
FlushMem is reached, Blitz sees there is no reference to
the image anymore, and deletes everything in the object:
variables, references to media like textures...everything
what may exist in the object, or type.


Hotcakes(Posted 2004) [#17]
Sounds about right to me...


FlameDuck(Posted 2004) [#18]
Pretty much. The only gotcha I've come across is when working with streams, which still have to be closed manually.


skidracer(Posted 2004) [#19]
.. The *object* TIimage is *not* returned, just a reference
to the image. This is why you will need to release the image
manually and the garbage collector doesn't know anything
'bout it.


Not exactly.

A reference to the object TImage is returned. That TImage's internal count is incremented because it realises there is an integer reference to it lose in the system and to reduce that count in order for that TImage to be destroyed you must call Release so it can reduce the count.