How to completely remove a node and its children

I am developing an app that does very frequent redraws of the whole scene, i.e. dumping the entire scene and drawing a new one.

When I watch my app’s memory use in the task manager, I can see that it steps up every time the scene is redrawn, but no memory is released when I tear down the old scene, so it just keeps going up which eventually leads to a crash. I assume I’m not properly cleaning up the old scene before I start drawing the new one.

I’m using removeNode to delete the old scene. At first I thought calling removeNode cleaned up everything at and below the calling nodepath. But a bit of experimenting showed that if you keep a reference to a child nodepath, it won’t be cleaned up when you call removeNode on the parent. Does removeNode clean up children that don’t have any references? What is the most efficient way to clean up everything under a specified nodepath regardless of whether there are references to some of its children?


I don’t know about the behaviour of removeNode, but I suspect that you’re running into Python reference counting issues; specifically, that as long as a reference to an object exists (even if it’s locked in a cyclic reference to which you’ve lost the handles) then the related memory likely won’t be released, at least until the program is closed.

removeNode detaches the node from the scene graph and drops the reference, so that (assuming you’re not keeping any other references) it may be garbage collected.

Deleting a scene works like deleting any object in Python - you don’t, you just drop all the references to it, so that it is garbage collected.

Parents hold references to child nodes, though, so that’s why there’s removeNode() which also detaches the given node from the scene graph.

There is also removeAllChildren, but it doesn’t do any magical deleting either - it simply invokes removeNode on all children of the node, but this won’t have a particular benefit over removeNode if you cleared up your references correctly. In that sense, removeAllChildren doesn’t solve your problem, since the child nodes won’t be removed either until their references are cleared as well.

One thing to mention is that if you have used setPythonTag referring to another node on any of the nodes, you have created a circular reference which must be explicitly broken first before you drop your last reference.

removeNode is different from just dropping a reference and waiting for the garbage collector though. For example:

a = render.attachNewNode(‘Something’)
b = a

The last line in this code raises an is_empty assertion error, so a.removeNode() does delete the node even though a and b still reference the node path.

So presumably, traversing the whole scene graph and calling removeNode on each node path would tear down the whole scene and release memory regardless of there being any references to some of the node paths. Those references would just become empty like the above code.

I’m just wondering if there’s a faster way to do this rather than manually traversing the whole scene graph.

I realize I was wrong in my last reply. A bit more experimenting has shown me what rdb was saying.

x.removeNode() removes that nodepath from its parent and drops the reference from x to the nodepath so the branch starting at x can be garbage collected.

But a single reference to any child of x will result in the whole branch not being garbage collected at all because node paths keep references to both parent and children.

I think circular references using setPythonTag might be the source of my memory leak. Thanks.