Operating system or device - Godot version: Windows 8.1 - Godot 2.1.x
Issue description:
When a variable is loaded via load("res://some_script.gd").new(), or SomeObject.new() it is not automatically freed when quitting the application, and there is an error message when closing the game window :
ERROR: SelfList<class GDFunction>::List::~List: Condition ' _first != 0 ' is true.
At: core\self_list.h:80
ERROR: SelfList<class GDScript>::List::~List: Condition ' _first != 0 ' is true.
At: core\self_list.h:80
WARNING: ObjectDB::cleanup: ObjectDB Instances still exist!
At: core\object.cpp:1845
ERROR: ResourceCache::clear: Resources Still in use at Exit!
At: core\resource.cpp:378
or:
WARNING: ObjectDB::cleanup: ObjectDB Instances still exist!
At: core\object.cpp:1845
Steps to reproduce:
extends Node
var object_from_script
var other_object
func _ready():
object_from_script = load("res://some_script.gd").new()
other_object = Node.new()
To try the bug with object_from_script, you need to create the script first, you can keep the default code in it. To test the two errors (see image), comment one of the two lines in the _ready() function.
How to avoid the error until it is fixed:
The only way I found to avoid the problem in my code is to add this piece of code:
func _exit_tree():
object_from_script.free()
other_object.free()
As objects created from the editors are automatically freed, I think this is a real bug.
If it is a wanted behaviour, I'd like to know a less redondant way to avoid it ;)
Link to minimal example project:
Here is the test project I used:
bug report.zip
is not should be handled manually?
what about assigning instance out of class?
Node A
extends Node
var object_from_script
var other_object
func _ready():
pass
Node B
extends Node
var instance_a
var instance_b
var node_a
func _ready():
instance_a = load("res://some_script.gd").new()
instance_b = Node.new()
node_a = preload("res://NodeA.tscn").instance()
node_a.object_from_script = instance_a
node_a.other_object = instance_b
add_child(node_a)
node_a.queue_free() # now instance_a & b should be freed automatically?
_edit code : NodeA.new() -> preload("res://NodeA.tscn").instance()_
I still get the same error.
However, I changed your code a bit and replaced
node_a = NodeA.new()
by
node_a = preload("res://NodeA.tscn").instance()
The main scene was NodeB.tscn
yes. you should be same error.
what I was trying to say is that automatically free() will cause problem in this case.
Ah OK, sorry ^^
However I don't see the real problem in your code...
instance_a and instance_b are defined in NodeB, and referenced in NodeA. When you free NodeA, you just remove the references but the original objects are still here.
Tell me if I'm wrong, but I think instance_a and instance_b should be automatically freed when NodeB is freed, as they are defined "inside" NodeB.
From here in the docs, I understand that objects are automatically deleted.
But from there, I understand the opposite... I am completely lost...
@MattUV one doc is from Reference and the other from Object.
In the case of References, I've thought they were removed when count was zero but got a leak while removing Nodes from the tree, so, that seems is not exactly how they work, docs need better explanation on Reference.
Better than what you are trying to do is to override _notification
and check NOTIFICATION_PREDELETE
and free all the Objects you need.
Sometimes you may want to exit tree and keep the variables, or to remove a node and keep some variables somewhere else.
Also check weakref that may be useful on some situations
http://docs.godotengine.org/en/stable/classes/class_weakref.html.
Lifetimes is not too complicated in GDScript, it just depends of the type:
Object
Must be freed manually by calling free
.Reference
: Freed automatically when the reference count reaches 0.Node
:queue_free
.Object
. Must be freed manually by calling free
.About @eon-s doubt on Reference in GDScript:
The refcount is incremented on assign, pass as argument, etc. It's decremented...:
Members: when the instance is freed.
Locals: it's a bit weird in this case though. You would expect it to be on scope exit like in C++, but it's actually on function return. However, and this is the weird part, if there are two locals at the same stack address, the refcount is decremented when the latter local is first assigned. e.g.:
func hello_there():
if whatever:
var myref = Reference.new()
print(myref)
# myref is still alive here, after exiting its scope. it's not visible though
return # the refcount for myref is decremented here, it's freed since it reaches 0
func oh_its_you():
if whatever:
var myref = Reference.new()
print(myref)
# myref is still alive here, after exiting its scope. it's not visible though
if whatever:
# myint is on the same stack address as myref,
# therefore it replaces the Variant at that address.
# the previous Variant at that stack address (the one for myref) dies,
# so the refcount for myref is decremented here instead
var myint = 10
print(myint)
return
I just checked your example project. You forgot to add the newly created nodes as children:
func _ready():
object_from_script = load("res://some_script.gd").new()
add_child(object_from_script)
other_object = Node.new()
add_child(other_object)
This way they are in the scene tree and the parent will free them automatically when freed.
If you don't do this, not only you must free them manually, but features like _process
or _fixed_process
won't be usable.
Here is a recommendation, always use add_child
and let the parent control the lifetime of your node, unless you know exactly what you are doing.
Could it (on debug) try to be more precise on the instances and Resources that still exists? Like trying to show the type, ID and name if apply?
Thank you all for your answers!
I guess this issue can be closed now, as it is not a bug, but a mistake as was making.
We can keep it open for eon-s's suggestion, or create its own suggestion thread ?
We could try showing the number of unparented nodes in the debugger
On May 30, 2017 10:51 AM, "Matthieu Huvé" notifications@github.com wrote:
Thank you all for your answers!
I guess this issue can be closed now, as it is not a bug, but a mistake as
was making.We can keep it open for eon-s's suggestion, or create it's own suggestion
thread ?—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/godotengine/godot/issues/8985#issuecomment-304884595,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AF-Z25Ioznt6Ue9KBq62snYD9cdXQHaHks5r_B7sgaJpZM4NpjQ3
.
if anyone wants to work on this... otherwise kicking to 3.1
@neikeq can u explain more on why it isnt getting deleted, if your script extends node and you instance it, what is it considered to be? a node an object or a reference?
if you do this:
func _process(delta):
var object = load('res://script.gd').new()
if you dont add it as child of a node, and if its considered a reference shouldnt it be deleted automatically on runtime?
if u use the code above and check godot monitor it shows object count rising and never stops
Node doesn't inherit from Reference, so it won't behave like one.
In your example the node object will leak as nobody is destroying it (but if you would add it to the tree then that would destroy the node).
TL;DR: Node
s aren't Reference
s
I have fallen for this myself and in my mass of code, I can't find which reference is not being freed. It would definitely be useful if it could output or give an indication of where the problem is. Right now I need to go through my code bit by bit to try and work out what is left behind.
@matty if you run Godot with the -v
flag (for verbose
) it'll list which objects were not freed when you close the game. Note that you need to run the game with the flag, not the editor.
@vnen Found it with that thanks. When I am changing scenes I am simply removing the scene with _current_view.remove_child(scene_name)
and then doing _current_view.add_child(scene_name)
.
For some reason, the entire scene that was previously removed gets leaked and all its resources. Does remove_child not free up the resources then?
Does remove_child not free up the resources then?
I wouldn't think so because that's generally used to remove it from one part of a tree only to add it to another part later.
@OvermindDL1 Ok thanks. My game is quite unique it is creating nodes dynamically all the time e.g I have a TileMap highlighter that is created & added/removed to the tree on mouse over tiles. When closing the app it is no longer in the tree so this also leaks.
Swapped it around to always be in the tree and use hide and show anyway.
I think probably some tool to check stray nodes and cyclic references should be created... but will kick this to 3.2 given we are feature frozen
The debugger's "Monitors" panel can now show orphan nodes:
Most helpful comment
We could try showing the number of unparented nodes in the debugger
On May 30, 2017 10:51 AM, "Matthieu Huvé" notifications@github.com wrote: