Best Way To Destroy An Object?

What is the best way to destroy an object in Xojo for garbage collection, or should I not even care? If I create an object - such as Dim X as MyClass - do I need to get rid of it when done?

I’m used to setting objects to Null when I am done with them, so that the GC can come along and recover memory etc.

You’re already doing it correctly. Xojo’s built-in garbage collection is actually the only way to destroy objects, which it does after detecting that all references to the object have disappeared.

OK, so something like “X = Null” is the right way to do it?

Yes, set the reference to nil. Or just let it go out of scope at the end of the method. Either way works. If you Var an object reference and use var X = New abc, the object will be destroyed when the method ends. You really don’t need to do anything special.

Technically, Xojo doesn’t do garbage collection. It uses reference counting. The moment the reference count drops to zero, the object is destructed. This happens inline with the rest of your code. Eg.,

Var X as New AbcObject
// X.Constructor happens here
...
X = Nil
// X.Destructor happens here immediately, before any other code runs
3 Likes

It’s important to remember that all references to your object must be nil before the object will be destroyed. So if you’ve handed off a reference, such as:

someOtherObject.x=myObject
aDictionary.Value("blergh")=myObject
aDictionary.Value(myObject)=true

…any of those references will be sufficient to prevent myObject from being destroyed. You will need to nil those references:

someObject.x=nil

The reference counting only works in one direction, so if someObject holds a reference to myObject, that won’t prevent someObject from being destroyed. Once an object is destroyed, any references it carries are also destroyed, so this would allow myObject to potentially be destroyed as well if there were no other references to it.

A good way to detect “leaking” objects is in the Debugger’s Runtime > Contents stack. This is a chronological list of all objects in your application. If you see something in there that you are positive should have been destroyed, that means that there is a lingering reference to it that is preventing its destruction.

Since it seems like you may be new to this kind of reference counting system, I would like to suggest that during the development of your application, you periodically do some validation to ensure that your objects are being destroyed as expected, and take the time to track down any issues. This kind of Destructor discipline will serve you well in the long term.

1 Like

The worst of these object reference issues is a type of deadly embrace. That is were object A contains a reference to object B and object B contains a reference to object A. The exact opposite of mutually assured destruction (mutually assured preservation).

To avoid a lot of Nils, one fast trick is creating a forced scope as

If True Then
  Var a As New Obj1
  Var b As New Obj2
  Var c As New Obj3
  Var d As New Obj4
  Var e As New Obj5
  process(a,b,c,d,e)
End
// a,b,c,d,e will be discarded here

Some languages have proper syntax for scopes without such tricks, more like:

Begin
  Var a As New Obj1
  Var b As New Obj2
  Var c As New Obj3
  Var d As New Obj4
  Var e As New Obj5
  process(a,b,c,d,e)
End
// a,b,c,d,e will be discarded here

That’s only true if process() doesn’t create a retained reference to any of its parameters.

The idea in the example is just take the content, process it and that’s it. Everything local without exporting retentions. All its locals will be also released at the function end as a good design usually does.

Well, that’s an important caveat for someone who’s just learning how reference counting works. It may not be obvious that if process() takes a parameter and stores it in a dictionary, for example, that this is a reference that has to be taken into consideration. This is exactly where people get tripped up.

If such dictionary is local, used just in such processing, it is ok. No caveats. Such problems arise when you “export” the problem, like storing things on a Global scope, for example. You local scope ends, but your referenced content lifetime continues outside.

An object-local scope would also create a problematic reference:

me.someDictionary("whatever")=obj1

The thing about reference counting is that issues spread like a wildfire. If you have an object that doesn’t destruct properly, anything it holds a reference to will not destruct, and so on - it’s a chain reaction of leaked memory.

That’s why I got into the habit of periodically checking my code for leakage. It’s a lot easier to catch it early rather than have 100 leaked objects and wondering which of them is the problem child.

What’s me? That’s not local

Local is

Function f(obj1 As Object)
  Var d As New Dictionary // local dictionary
  d.Value("whatever")=obj1
End // d is released here, obj1 loses one ref count from it too

I thought Xojo used Reference Counting and not GC.

I find the best way to destroy things is fire, eventually you can reduce anything to dust.

1 Like

Re-read my comment: object-local, ie a property of the object.

That’s not local scope, that’s an external scope. The reference will belong to an external object not in the local scope and will only released when that reference is nulled or such container object released, releasing its references too.

We can argue semantics if you want, but the point of my comment stands.

Yes, but not everyone knows the difference.
It is just magic for most developers and nothing to think about.

1 Like

We shouldn’t, all your questions were extensively explained.

I don’t know what’s your point. If it is that bad programming not releasing references implicitly or explicitly can cause leaks, I agree.

Really… Oh boy…