• Godot Help
  • What happens to a coroutine if the object is destroyed?

As I understand, when you use yield or await, a coroutine is created that will execute some code when some conditions are met. In the case of await, the coroutine runs when a certain object emits a certain signal. I wonder what happens to coroutines when the object it's waiting the signal from is destroyed.

example:

var newThing = thing.instantiate()
add_child(newThing)
await newThing.countToTen
print("thing counted to ten)

What happens to the coroutine waiting to print if the newThing is freed before it emits "countToTen"? Will it just accumulate in memory and cause a memory leak?

So I could see two cases. Either the coroutine is orphaned, and still exists running and taking memory but probably not working properly or causing undefined behavior.

Or the call to queue_free or free will fail, and the object will never be destroyed. In either case, it will probably mess up your game.

Nothing special happens. Only that the code following await will never execute. There will probably be some memory leakage for each unanswered await as the coroutine stack frame needs to be stored somewhere. However it's also possible there won't be any leaks if engine cleans up the coroutine when signal source is destroyed. We should ask devs about it or look at the source. It can also be tested. Run a bajillion of orphaned coroutines and see what the profiler says about memory usage. If nothing remarkable happens it means that coroutines get destroyed.

But why use await here when you can just have a regular signal handler?

    xyz Please let me know if you get any answers from the devs.

    As for the use of await, it's just really convenient in some situations where I realize half-way through the code that I need to wait for a signal. In other words: yes, it's possible to refactor the code to not have await anywhere, but it's convenient to use it sometimes.

    • xyz replied to this.

      GE100 Please let me know if you get any answers from the devs

      By "we should ask devs" I meant you 😉. I don't have any special powers to talk to devs. If you're interested it this - ask them. But as I said, it's trivial to check.

      Case when the signal source is deleted:

      extends Node
      func _process(delta):
      	var n = Node.new()
      	add_child(n)
      	n.queue_free()
      	await n.renamed

      Case when it's not:

      extends Node
      func _process(delta):
      	await self.renamed