What is the difference between queue_free() and call_deferred("queue_free")

Godot Version

Godot 4.x (4.2+)

Question

I was watching a tutorial video in which the author first used queue_free() in a signal to free a node after the player picked it up, but then he said it was better/safer to use call_deferred("queue_free") to avoid freeing the node in the middle of a physics tick.

(I assume that queue_free.call_deferred() is essentially the same thing as call_deferred("queue_free") but the first one has the benefit of auto-completion and avoiding potential typos due to not using a string. And while personally I would use the first form in my own code, throughout the rest of this post I’ll be using the latter form because that’s how it was shown in the tutorial video.)

The problem is as follows:

I was under the impression that queue_free() already waited until the end of physics/process frames so using call_deferred("queue_free") is unnecessarily redundant, essentially accomplishing the same thing that queue_free() would do on its own.

The author and I engaged each other in the comments and neither of us were entirely confident in our positions. I did some searches to try and find an answer but mostly only found people asking about the difference between queue_free() and call_deferred("free") which is an entirely different question.

So then I asked an AI to summarize the difference for me and it said queue_free() schedules the deletion of the node at the end of the current frame while call_deferred("queue_free") schedules the deletion of the node at the beginning of the next frame which “allows it to clean up any resources it has allocated” first.

Meanwhile, the official documentation on Callable.call_deferred() says:

Calls the method represented by this Callable in deferred mode, i.e. at the end of the current frame. Arguments can be passed and should match the method’s signature.

And for Object.call_deferred() it says:

Calls the method on the object during idle time. Always returns null, not the method’s result.

Idle time happens mainly at the end of process and physics frames. In it, deferred calls will be run until there are none left, which means you can defer calls from other deferred calls and they’ll still be run in the current idle time cycle. If not done carefully, this can result in infinite recursion without causing a stack overflow, which will hang the game similarly to an infinite loop.

Which sounds to me like the AI was wrong (no big surprise there!) and call_deferred("queue_free") also schedules the deletion of the node at the end of the current frame.

All of that to say that I’m still not sure there’s a practical difference between queue_free() and call_deferred("queue_free").

Is there a difference? And if so, can someone please explain to me what the difference is and under what circumstances one would be preferred over the other?

Mine too.

I suspect this is a mistake in the tutorial where they may not be aware node.free() exists and thought queue_free() did the same thing.

call_deferred(“free”) is mostly equivalent to queue_free() as I understand it, though functions differently. Queue_free pushes the node into a delete queue which is not flushed until the end of the physics/process^ functions respectively.

Now I think about it, call_deferred(“queue_free”) possibly forces the delete to occur at the end of the NEXT frame, as it’s effectively calling queue_free() at the end of the current frame (I assume _call_idle_callbacks) which just adds the node to the delete queue and is not assessed until the following frame. So if anything it’s detrimental.

^Given the process order of _process and _physics_process differs slightly re. deletions, I would be hesitant to suggest using call_deferred(“free”) even, as it seems conditionally tweens should be processed after removal within the same frame.
Just stick with queue_free(), it exists for a reason and if it causes any issues with deletion of physics object this is a bug that should be reported, not worked around with some undocumented hoodoo.

4 Likes

Reading the Godot’s source code one can see that the handling of all kinds of stuff substantially changed between Godot 3 and 4. So I’m answering from a Godot 4 perspective. The most relevant pieces of code are in scene/main/scene_tree.cpp.

Godot does processing of deferred function calls as part of its message queue flushing (MessageQueue::get_singleton()->flush()) as far as I can tell. And freeing of queued objects happens when _flush_delete_queue() gets called.

Both of those are performed during physics frames/steps (SceneTree::physics_process) as well as render frames (SceneTree::process). That already tells us that objects queued for deletion during physics processing get freed at the end of a physics time step and don’t stay around until the end of the render frame (unless you call queue_free() during _process() or outside of physics processing, obviously).

The order when the message queue flushing happens vs. the delete queue processing is relevant to answer your question. As the message queue is flushed (and therefore deferred calls processed) before freeing queued objects, calling queue_free() from a deferred call or not doesn’t make a difference in Godot 4, as they will eventually be freed during the same _flush_delete_queue() run.

(Had the order in the C++ code been the other way around, things would be different as calling queue_free() in a deferred fashion would enqueue the object for freeing after the current frame’s _flush_delete_queue() run and would therefore stick around until the end of the next physics or render frame - whichever happened first.)

I haven’t really examined the old Godot 3 code, though, so I can’t say for sure what happened there other than it being structured completely differently. So it may possibly have been different when you used old Godot 3.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.