How to Free Memory/Resources/Refcounted?

Godot Version

V4.6.2 Stable

Question

Hi All,

I believe I am having an issue understanding freeing Objects/Resources/Refcounted. From the Godot documentation I gather that RefCounted objects are automatically removed when all their references are null whilst objects require removal via free().

My game is very resource heavy as its a card game and In my game I need to run simulations for AI moves. Therefore I duplicate the instance of my battle state and everything other instance in it (they all extend from either Resources or Refcounted). However on completion of the simulations, the objects aren’t freed.

Is there a specific process I should be following specifically for simulations? Since the simulated states aren’t linked to anything in particular in the scene tree, it seems they just sit there, somewhat linked between themselves in some nightmarish web (even though I try to limit any circular dependencies). Surely its not an expectation to write a cleanup script on each one, manually setting each reference to null and disconnecting every signal right?

Why isn’t it as simple as “The SimState class holds a reference to the new simulated battle, when I free it, the battle state and everything from it should be removed too”? Or is there a garbage collection option in Godot? Essentially everyhing I create from a certain point in time I want it all freed on completion?

Also is there a way i can view the classes of the objects that remain in my scene so I can determine which ones are hanging around (e.g. via a log)?

While I don’t have much experience with “dry runs” to help you with best practices for these simulations, it sounds like its moreso that your issue is to do with lifetime owernship.

Unfortuantely the ideal solution here is to truly untangle that dependency web, and establish clear one-direction relationships between these Resources/RefCounteds. This will inherently solve the problem of lifetime ownership, but if you want to limit refactoring, a faster but brittle way to achieve this is by using WeakRefs:

For any object that you believe shouldn’t control the lifetime of another object, when assigning a reference you can wrap the value in a weak ref like so: var weak_ref : ResourceType = weakref(the_resource). These WeakRefs won’t increment the reference count so if done right, when you free() the outermost owner, the rest will follow.

If you want a different approach you could convert them to nodes and setup up an attachment chain that you can then “pop from the top” via queue_free() on the outermost Node. I’m still learning Godot though so I yet don’t know how performance heavy Nodes are compared to Resources/RefCounted.

For your final question about profiling/inspecting the current object counts, in the debugger there is a tab called ObjectDBProfiler. In here you can take snapshots of the running instance, where you can then view the object counts of specific classes.

How did you determine that?

Duplicate or deep duplicate?

According to the array documentation, duplicate creates references to the original objects. deep_duplicate is needed for new objects.

If you are just copying, the original objects will be maintained. Which could result in the behavior you are seeing.

I checked the objects in the monitor debugger. They never erase on completion of the simulation.

Neither technically. I made my project before deep duplicate was a thing, therefore I had issues with referencing. So I created my own duplicate_instance function where I create a clean new instance, then manually assign the elements that I need (except references if not needed) from the base object.

Which objects?
Post the duplication code.

You never need to worry about resources and other ref counted object. They are managed. That’s the whole purpose of reference counting. You also don’t need to worry about any child nodes. When you delete the parent, its complete node hierarchy will be cleaned as well. The only thing you really need to take care of are orphan nodes.

Thanks for the idea. Likely that is the right path but is so frustrating for a resource heavy game with many references. Weirdly it’s just something I never thought of. I honestly hoped I could just delete the SimGameState instance and be done with them but that’s a learning curve for me I guess.

I do with there was a function to just remove all signals though. That will be a pain checking for connections each time and removing them.

There is a very small chance that it’s a bug. So it’s probably about the logic you do that is still referencing the RefCounted even though you think it’s not.

It’s hard to figure it out without seeing the related code.

It’s not recommended but you can use unreference() on the RefCounted if you really think it should not be referenced anymore. But, I feel that may cause more issues if you are missing something in your logic.

You can see the active objects/resources in the debugger/monitor.
You can also see the reference-count by calling get_reference_count() on the resource.
But as many people already said, ref-counted are handled for you, so as long as you dont have cyclic references you dont need to worry about them

Thanks for your help everyone.

I investigated further using the Object Profiler (it wasn’t working properly yesterday, it didn’t let me take snapshots but its working now).

Essentially i store the context of game actions as well as Effect Results for some functional purposes but also UI purposes, this is causing a lot of circular dependancy. It’s the right way I should implement it but it just means I need to make sure I run a cleanup function on them to disconnect everything, otherwise they just sit there keeping everything alive.

I’ll just make a few cleanup functions and that should solve the problem as @kDoesDev suggested.

Although I don’t believe the Node method will work as he suggested (I initially thought up the same thing) basically since you’ll need so many nodes the instantiation would seriously affect performance (at least for my game it will).