Empty Type objects
BlitzMax Forums/BlitzMax Beginners Area/Empty Type objects
| ||
Okay so I understand that there is no "Delete" command (well, there is, but it's not the same as used in BB) I also understand that there is a Garbage Collection that will a(by default) automatically deallocate memory from null objects at certain intervals to plug any memory leaks. So is it correct to simply set an existing instance = null if I want to 'delete' it? (Obviously ensuring to free any handles within that instance's fields where appålicable) It feels like it's not a 'good' approach... |
| ||
As soon as nothing has a handle to an object anylonger, this object will be GC'd sooner or later. This makes it important to _not_ crosslink objects together without paying attention to it. So do not do this: you could check it out by having custom "Method Delete()" in your type and print a "I get garbage collected" there... Then "GCCollect()" and see what happens. Edit: I extended my sample: bye Ron |
| ||
I tried putting in a delete method that would write to the debuglog and then call a destructor - this was when I realised there WAS no destructor :) Thanks for the reply. I'm not intending anything too complex at the mnment, letä' say for example, a space invaders game - once the players bullets reach the top of the screen and no longer necessary how would one recyle or otherwiae deal with those resources? In BB one would need to track the Y directoin and then delete them as required: i.e. Function UpdatePlayerBullets() Local Iterator.PlayerBulletType For Iterator=Each PlayerBulletType Iterator\Y=Iterator\Y+1 If (GetAlienCollision(Iterator\x,Iterator\Y)) KillAlienFunction() Else If (Iterator\Y>SCREEN_LIMIT) DestroyPlayerBullet(Iterator) End If End If Next End Function ;This is the destructor function as in standard BB Function DestroyPlayerBullet(Instance.PlayerBulletType) If (Instance<>Null) DebugLog(Str(Instance)+" Destructor call") If (Instance\Image)Then FreeImage Instance\Image Delete Instance End If End Function As I can see in BMax there is no way to either Free the image, nor Delete the type, but I am also not seeing how to notify the garbage collector that that particualr instance (i.e. one that has reached the top of the screen for example) is no longer wanted... |
| ||
You do not need to manually free "GC-managed objects" (so normal Blitzmax-stuff). So how to handle it? If you have a list of bullets, or an array, or a map ... just remove the bullet from this list/array/ and it will get deleted automatically (except something holds a reference to it ... then it is only removed from memory once this references are cut too). (untested, just written as example) Type TBullet global allBullets:TList = CreateList Function AddBullet(bullet:TBullet) if not allBullets.contains(bullet) then allBullets.Addlast(bullet) End Function Function UpdateBullets() 'to avoid concurrent list modification, we hold an array 'of "now-dead"-bullets 'else we would modify the list while iterating over it (bad!) local toDelete:TBullet[] for local bullet:TBullet = EachIn allBullets bullet.Update() if not bullet.IsAlive() then toDelete :+ [bullet] next for local bullet:TBullet = EachIn toDelete allBullets.Remove(bullet) Next End Function 'update an individual bullet Method Update() y :- 10 '* deltaTime or so... End Method Method IsAlive:int() return y > 0 End Method End Type bye Ron |
| ||
I tried putting in a delete method that would write to the debuglog and then call a destructor - this was when I realised there WAS no destructor :) The Delete method IS the destructor - or maybe finalizer would be the better term. It gets called when your object is deleted. But you don't normally need to write Delete methods, and you don't delete objects manually. The garbage collector will do it for you automatically (but not necessarily immediately) once you no longer have any references to them - in other words, an object can get collected when there are longer any variables pointing to it. That doesn't mean you have to set variables to Null all the time though. It suffices when the variables holding your objects go out of scope (for example, they were stored in a Local variable in a method or function and the function finished executing) or when they were stored in fields in another object (for example in an array or list) and that "outer" object gets garbage collected. The one important thing to be careful about, however, is the one Derron mentioned in post #2: don't leave any "circular" structures of objects pointing to each other behind, or they might not get collected ever. |
| ||
Just a note when using the Delete method. There is no guarantee that it will ever be called. The GC will determine the best time to remove the type, and if the program ends with types still in memory, they will be removed en-mass without calling the delete method. This means you don't want to put anything critical there, such as closing files.Type TMyType Field FileOut:TStream Method New() FileOut = WriteStream("MyFile.txt") End Method Method Delete() CloseStream FileOut 'You do not want this here. There is no guarantee it will be called End Method End Type Local MyFile:TMyType = New TMyType MyFile = Null 'This will put the type onto the GC's "Delete" stack, and Delete will be called 'when the GC removes the type from memory. But if the program ends 'before the GC removes it, Delete will never be called, and the file will be left opened |
| ||
So how to handle it? If you have a list of bullets, or an array, or a map ... just remove the bullet from this list/array/ and it will get deleted automatically (except something holds a reference to it ... then it is only removed from memory once this references are cut too). (untested, just written as example) This seems to suggest that (for example, as with the space invader bullets example) I MUST USE some form of array or list for such objects? And it is the removal of such from this list that invokes garbage collection of the referenced object? What else may hold such a reference and prevent such collection? Global instances? |
| ||
Lists are just typical for collections. As you already recognized: globals are one "reference holder". Imagine you have a function like this: Type MyType Field i:int = 1 Method Delete() print "I got deleted" End Method End Type Function Test:int() 'list is a "local variable" '->limited to the "function scope" '-> automatically removed at the end of the function local list:TList = CreateList() list.AddLast( new MyType ) End Function 'this will create the list within the function and add the new instance of "mytype". 'but afterwards, it will get garbage collected Test() Delay(10) GCCollect() But ... if the "list" was defined as "global list:TList" - it won't get deleted. So as soon as a variable goes out of scope, it is ought to get GC'd somewhen. -> it does not matter if it is a list / map / array holding things, it matters if the container is getting GC'd (local variables in a loop / function / ... - or if you "null" the variable). bye Ron |
| ||
Thanks Derron, that really helps a lot, sorry for being a bit slow on the uptake with this! :) |