Empty Type objects

BlitzMax Forums/BlitzMax Beginners Area/Empty Type objects

_PJ_(Posted 2016) [#1]
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...


Derron(Posted 2016) [#2]
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


_PJ_(Posted 2016) [#3]
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...


Derron(Posted 2016) [#4]
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


FireballStarfish(Posted 2016) [#5]
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.


TomToad(Posted 2016) [#6]
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



_PJ_(Posted 2016) [#7]


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?


Derron(Posted 2016) [#8]
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


_PJ_(Posted 2016) [#9]
Thanks Derron, that really helps a lot, sorry for being a bit slow on the uptake with this! :)