vtkDebugLeaks in slicelet

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?

Thanks in advance.

This page should help: https://www.slicer.org/wiki/Documentation/Nightly/Developers/Tutorials/MemoryManagement

Using the Unregister function on the slicer AboutToQuit method doesnt seem to work. See code sample below.

slicer.app.connect('aboutToQuit()', self.removeNodes)

def removeNodes(self):
        '''
        Remove nodes from scene to prevent vtk leaks.
        '''
        n = slicer.mrmlScene.GetNodesByClass('vtkMRMRLFiducialListNode')
        n.UnRegister(slicer.mrmlScene)

Also trying:

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)

This also didn’t work.

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.

What template did you use to create your slicelet?
Is your code available on github so that we can have a look?

(Note: spelling of the slicer applet term is “slicelet” not “slicelete”)

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)

Fwiw, instantiating a node using :

n = slicer.vtkMRMLViewNode()

Will avoid the use of UnRegister.

Hth
Jc

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)

hello.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>600</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget"/>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>21</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
 </widget>
 <resources/>
 <connections/>
</ui>

hello.py

# coding: utf-8
import slicer 
import qt

# Load UI file
uiloader = qt.QUiLoader()
file = qt.QFile("D:/project/slicer/Base/Python/hello.ui")
file.open(qt.QFile.ReadOnly)
dtcUI = uiloader.load(file)
file.close()

# set central widget
layoutMrml = slicer.qMRMLLayoutWidget()
layoutMrml.setMRMLScene(slicer.mrmlScene)

# this line will cause memory leak
dtcUI.setCentralWidget(layoutMrml)

dtcUI.show() 

I don’t know what and how to release the referenced vtk object ?

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.

Andras,

I am running the python script under self-compiled slicer (tag v4.8.1) and slicer will show me the vtkDebugLeaks message to me while closing.

According to your reply, do you mean the python code i showed should not necessary to release any vtk object?

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.