When I close my slicelete I always get an error box that says “vtkDebugLeaks has detected LEAKS!” and it lists a bunch of node types that still have instances. I am programming in python and I am not sure the proper way to resolve this. It even happens if I just open and close the app immediately. What can I do?
def removeNodes(self):
'''
Remove nodes from scene to prevent vtk leaks.
'''
n = slicer.mrmlScene.GetNodesByClass('vtkMRMRLFiducialListNode')
n.UnRegister(slicer.mrmlScene)
n = slicer.mrmlScene.GetNodesByClass('vtkMRMRLFiducialListNode')
for i in xrange(n.GetNumberOfItems()):
volume_node = n.GetItemAsObject(i)
slicer.mrmlScene.RemoveNode(volume_node)
volume_node.UnRegister(slicer.mrmlScene)
You don’t need to remove nodes from the scene on application exit, Slicer will take care of that.
In order that mechanism to work correctly, when you add a node to the scene then you should delete your reference to that node immediately, to let the scene take full ownership of that node. The scene will know when to delete that node (for example, when the node is removed from the scene or the entire scene is deleted).
For example, as shown on the wiki page I linked:
n = slicer.mrmlScene.CreateNodeByClass('vtkMRMLViewNode')
slicer.mrmlScene.AddNode(n)
n.UnRegister(slicer.mrmlScene)
The problem is that your code keeps a reference to a MRML node or some other VTK objects. It is usually very difficult to find source of memory leaks. One technique is to comment out parts of your code until the memory leak is gone. When the leak is gone then you will know that the part you commented out last causes the leak.
I am also having this issue before I add any nodes to slicer. I can launch the slicelete and close it immediately and still have a warning dialog pop up.
If you need help, we must understand your problem, and for that you always need to provide full error message and/or description of what you did, what you expected to happen, and what happened instead.
Note that (as described on the page that I linked) slicer.mrmlScene.GetNodesByClass creates a vtkCollection that must be unregistered immediately after you get the object in Python, otherwise the collection will not be destroyed and it will keep a reference to all the nodes inside it.
To remove all markup nodes from the scene (note that in Slicer4 there are no more fiducial list nodes):
nodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLMarkupsFiducialNode')
nodes.UnRegister(None)
for i in range(nodes.GetNumberOfItems()):
node = nodes.GetItemAsObject(i)
slicer.mrmlScene.RemoveNode(node)
Here’s snippets of code from @jks1995 regarding his issue.
Instantiating “Analysis” and “Acquisition” in ModuleEQ does not result in vtkdebug leaks even though layout_widget.layoutManager() is passed into them successfully as an argument and used in the destination file.
However, passing layout_widget as an argument into FileB, which is then added as a widget to layout, results in vtkdebug leaks upon closing of the slicelet.
from FileB import FileB
from Analysis import Analysis
from Acquisition import Acquisition
from __main__ import qt, slicer
class ModuleEQ():
def __init__(self):
'''
Instantiate all the major GUIs and their corresponding classes.
'''
layout_widget = slicer.qMRMLLayoutWidget()
layout_widget.setMRMLScene(slicer.mrmlScene)
layout_manager = layout_widget.layoutManager()
acquisition = Acquisition(layout_manager)
acquisition_gui = acquisition.getUI()
analysis = Analysis(layout_manager)
analysis_gui = analysis.getUI()
file_b = FileB(layout_widget, acquisition, analysis)
if __name__ == "ModuleEQ":
ModuleEQ()
Below is the second file where the layout_widget is passed into. FileB.py:
def __init__(self, layout_widget, acquisition, analysis):
self.layout_widget = layout_widget
self.acquisition = acquisition
self.analysis = analysis
self.setUpUI()
def setUpUI(self):
'''
Set up the user interface using the UI file.
'''
ui_filepath = os.path.dirname(os.path.realpath(__file__)) + '/FileB.ui'
ui_loader = qt.QUiLoader()
f = qt.QFile(ui_filepath)
f.open(qt.QFile.ReadOnly)
self.ui = ui_loader.load(f)
f.close()
#add acquisition and analysis gui into FileB gui
self.main_tabs = self.ui.findChild(qt.QTabWidget, 'main_tabs')
self.main_tabs.insertTab(0, self.acquisition.getUI(), "Ultrasound Acquisition")
self.main_tabs.insertTab(1, self.analysis.getUI(), "Image Analysis")
#add slicer views to Qframe in FileB gui
slicer_views_frame = self.ui.findChild(qt.QFrame, 'slicer_frame')
slicer_views_frame.setLayout(qt.QVBoxLayout())
slicer_views_frame.layout().addWidget(self.layout_widget)
I also encountered same problem with same mechanism. (use QUiLoader to load a ui and set central wiget to qMRMLLayoutWidget will get vtkDebugLeaks while closing application)
I’m not sure what the issue is, but in production code you should probably disable memory leak checking (by turning off Slicer_USE_VTK_DEBUG_LEAKS CMake flag when configuring Slicer build). In the latest stable (Slicer-4.8.1), no memory leaks are reported; in nightly builds, some builds may have Slicer_USE_VTK_DEBUG_LEAKS option enabled.
If memory leaks are reported then it means that you either have to release some resources (delete variables, set references to objects to None, etc.) or tune the order of object deletion.
Examples on Slicer’s slicelet page work without memory leaks, you can start from those and see which of your change introduces the leak - then you know exactly where to look for the root cause of the issue.
You may also choose to keep the Slicer main window and hide all custom elements (toolbars, menu bars, etc.) that you don’t need.
Disable Slicer_USE_VTK_DEBUG_LEAKS when you are configuring your Slicer build if you don’t want to see debug leaks report during development. Always disable Slicer_USE_VTK_DEBUG_LEAKS in software that is shipped to customers.
My first version is using that method to customize our own UI with no leaks but after we trasferring to use QUiLoader to load Qt widgets and set slicer.mrmlScene to QMainWindow main widget, application will report leaks after closing.
I am wondering slicer.mrmlScene will also be referenced while we set main widget of QMainWindow to mrmlScene and it’s necessary to set main widget to None before closing app.