Not able to queue free orphan nodes

Godot Version

4.2.1

Question

I was able to determine where my orphan nodes are coming from, but now I am not able to properly remove them. I have this part of the code:

var test_state:GameState = GameState.new()
test_state.name = "TestState1"
test_state.positions_pieces = positions_pieces.duplicate()
test_state.active_color = active_color
test_state.castling = castling.duplicate()
test_state.en_passant = en_passant
test_state.halfmove = halfmove
test_state.fullmove = fullmove
test_state.fen = fen
test_state.state = state
test_state.result = result
test_state.pieces_left = pieces_left
var result_state:GameState = GameState.new()
result_state.name = "ResultState1"
result_state = test_state.perform_move(result_moves[move])
result_state.positions_pieces = test_state.positions_pieces.duplicate()
result_state.active_color = test_state.active_color
result_state.castling = test_state.castling.duplicate()
result_state.en_passant = test_state.en_passant
result_state.halfmove = test_state.halfmove
result_state.fullmove = test_state.fullmove
result_state.fen = test_state.fen
result_state.state = test_state.state
result_state.result = test_state.result
result_state.pieces_left = test_state.pieces_left
for result_move in result_state.get_valid_moves(0):
	if result_move[2] > -1:
		if result_move[2] == result_state.get_king_position(active_color):
			result_moves.remove_at(move)
			break
test_state.queue_free()
result_state.queue_free()

The output from print_orphan_nodes show this when closing the game:

85698022361 - Stray Node: ResultState1 (Type: Node)
85765131229 - Stray Node: ResultState1 (Type: Node)
85832240097 - Stray Node: ResultState1 (Type: Node)
91653934050 - Stray Node: ResultState1 (Type: Node)
85899348965 - Stray Node: ResultState1 (Type: Node)
91721042918 - Stray Node: ResultState1 (Type: Node)
85966457833 - Stray Node: ResultState1 (Type: Node)
92660567023 - Stray Node: ResultState1 (Type: Node)
92727675891 - Stray Node: ResultState1 (Type: Node)
92794784759 - Stray Node: ResultState1 (Type: Node)
92861893627 - Stray Node: ResultState1 (Type: Node)
92929002495 - Stray Node: ResultState1 (Type: Node)

As you can see, I’m using queue_free() to remove the result_state after using it, but it seems that it remains in the memory. How can I remove them?

var result_state:GameState = GameState.new()
result_state.name = "ResultState1"
result_state = test_state.perform_move(result_moves[move])

Here you create a new GameState… and then overwrite the reference with an entirely different allocated object!

My hunch is that if you print the name of result_state before you queue_free it, you will not get “ResultState1”

Let me know if that’s correct :slight_smile:

2 Likes

Indeed, is getting “TestState1”. What am I missing here?

In the first line you tell the game that you want to allocate a new chunk of memory on the Heap for a GameState with GameState.new(). At that point result_state is a reference to a fresh new GameState object. It’s looking at a specific memory address on the heap and reading/writing to the GameState there.

var result_state:GameState = GameState.new()

In the second line you modify a property of that GameState.

result_state.name = "ResultState1"

In the third line, I’m not entirely sure what test_state.perform_move does, but I’m assuming it returns a reference to the owner of the perform_move function. Now result_state is a reference to a completely different block of memory on the Heap or the Stack.

result_state = test_state.perform_move(result_moves[move])

At this point your GameState you declared on line 1 is Orphaned. Nothing has a reference to it :frowning:, and you’ve caused a memory leak! You’ve allocated memory for the GameState but never tell your computer that you’re done using it using queue_free.

And later, when you call result_state.queue_free(), the node/object that you free is a completely different GameState. My hunch is that it’s the GameState you declared on your very first line.

var test_state:GameState = GameState.new()

AKA, you’re calling queue_free on the same object, twice!

test_state.queue_free()
result_state.queue_free()

Hope that helps! Memory management is a difficult topic in CS and Godot does somewhat obfuscate it. Here’s a link to what the docs have to say as well.

1 Like

Hmmmm, that’s very insteresting! Thanks for the explanation.

The method perform_move returns a GameState with the new positions and state of the game (this chunk of the code is being used to simulate plays). Maybe it would be better to just assign the GameState that returns from the method?

var result_game:GameState = test_state.perform_move(result_moves[move])

That would work! Just keep in mind that right now you’re probably modifying and then returning the GameState that owns the perform_move method, in this case whatever is referenced by test_state.

If you want a different instance of a GameState you need to allocate one with GameState.new(). That way you could have one GameState the represents the board before the move, and another that represents the board afterwards.

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