IDisposable & Free() in C#

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By permal

Hi,

Godot.Reference andGodot.Object directly or indirectly implement IDisposable. They also provide the Free()method.

How are we meant work with these two different memory management designs? Are we meant to call both Free() and Dispose() or just one of them from C#?

:bust_in_silhouette: Reply From: betauer

Object.Free() and Node.QueueFree() methods are just the C# counterparts of their GDScript methods. Dispose() is a pure C# method that you can implement and call when you consider. For every Godot.Object you have in C#, Godot already has another native object linked, so your C# object is just a bridge between your C# code and the native Godot object (you can access to the IntPtr using the Godot.Object.NativeInstance property)

The Godot.Object.Dispose implementation just calls to another Dispose(bool disposing) virtual method, so you can override it safely to dispose another objects if you need it. This virtual method calls to godot_icall_Reference_Disposedor godot_icall_Object_Disposed to free the memory of the native godot object.

If you never free the objects, Godot engine will try to free them for you when reference count is 0 in case of Reference or when the game is shutdown in case of orphan Nodes or Objects, and the Dispose method will be called (the bool disposing parameter will be false in case of shutdown). Also, the C# Garbage Collector could try to free it at some point in the future if it consider it. When the GC destroy the C# Object, the Dispose() method will be called, so the Godot engine will be noticed, freeing the native Godot object.

It’s a good practice to override the Dispose(bool disposing) method and put more code there to dispose resources: just don’t forget to call to base.Disposing(disposing) inside, or the native godot object will not be freed. More information about the usage of the IDisposable pattern here: When and How to Use Dispose and Finalize in C# - DZone

So, different behaviours can be achieved:

  • If you call to the Free() method, the object will be freed immediately in Godot. This is useful when you want to get rid of the object as soon as possible. Sometimes you can’t use if: for instance, you can not free an object when you are inside of the method called by a signal emitted of the same object. Then you have to use QueueFree() instead, but this method is only available for Godot.Node. An alternative way could be wrap the method in an async method and await for the next frame with await sceneTree.ToSignal(sceneTree, "idle_frame");, and call to the Free() method after it.

  • If you call to the Dispose() method, you can be sure the C# resources will be freed immediately (I mean, the Dispose(bool disposing) method will be called), but the Godot instance will not be freed immediately.

More information about Dispose() and Dispose(bool disposing) pattern: When and How to Use Dispose and Finalize in C# - DZone

betauer | 2022-01-25 21:20