[vtkusers] When must I be weary of Python garbage collection?

Elvis Stansvik elvis.stansvik at orexplore.com
Wed Feb 24 04:46:05 EST 2016


Hi all,

Sorry if this is an obvious question, but I could only find a few mails in
the archive about Python memory management and VTK.

My question is when I need to be weary of the Python garbage collector when
setting up a VTK pipeline.

Consider the cone example from QVTKRenderWindowInteractor:


def QVTKRenderWidgetConeExample():
    """A simple example that uses the QVTKRenderWindowInteractor class."""

    # every QT app needs an app
    app = QApplication(['QVTKRenderWindowInteractor'])

    # create the widget
    widget = QVTKRenderWindowInteractor()
    widget.Initialize()
    widget.Start()
    # if you dont want the 'q' key to exit comment this.
    widget.AddObserver("ExitEvent", lambda o, e, a=app: a.quit())

    ren = vtk.vtkRenderer()
    widget.GetRenderWindow().AddRenderer(ren)

    cone = vtk.vtkConeSource()
    cone.SetResolution(8)

    coneMapper = vtk.vtkPolyDataMapper()
    coneMapper.SetInputConnection(cone.GetOutputPort())

    coneActor = vtk.vtkActor()
    coneActor.SetMapper(coneMapper)

    ren.AddActor(coneActor)

    # show the widget
    widget.show()
    # start event processing
    app.exec_()


In this example, the program will block on the app.exec_() call, while
still inside the QVTKRenderWidgetConeExample() and with all the created
variables thus "alive". So no fear of them being garbage collected.

But what if I instead moved this pipeline setup code into the __init__ of a
QVTKRenderWindowInteractor subclass, like this:


class MyWidget(QVTKRenderWindowInteractor):
    def __init__(self, *args, **kwargs):
        super(MyWidget, self).__init__(*args, **kwargs)

        self.Initialize()
        self.Start()

        ren = vtkRenderer()
        self.GetRenderWindow().AddRenderer(ren)

        cone = vtkConeSource()
        cone.SetResolution(8)

        coneMapper = vtkPolyDataMapper()
        coneMapper.SetInputConnection(cone.GetOutputPort())

        coneActor = vtkActor()
        coneActor.SetMapper(coneMapper)

        ren.AddActor(coneActor)


This works, Python is not performing garbage collection of anything,
despite me not keeping the involved variables (renderer, source, mapper,
actor) as fields of my class. I suppose this is because a reference to the
renderer is kept in the render window, which is kept in the base class, and
the renderer holds the actor, which hoids the mapper, which holds the
output port of the source. So nothing is eligible for garbage collection.

So my question is, can I always rely on this behavior when working with
pipelines through the Python wrappers? Or are there cases where VTK will do
things in C++ "behind the back" of the Python garbage collector?

The ultra-safe way is of course to keep explicit references to everything:


class MyWidget(QVTKRenderWindowInteractor):
    def __init__(self, *args, **kwargs):
        super(MyWidget, self).__init__(*args, **kwargs)

        self.Initialize()
        self.Start()

        self.ren = vtkRenderer()
        self.GetRenderWindow().AddRenderer(self.ren)

        self.cone = vtkConeSource()
        self.cone.SetResolution(8)

        self.coneMapper = vtkPolyDataMapper()
        self.coneMapper.SetInputConnection(self.cone.GetOutputPort())

        self.coneActor = vtkActor()
        self.coneActor.SetMapper(self.coneMapper)

        self.ren.AddActor(self.coneActor)


And in fact, most of the time you probably want to keep references to a lot
of things, to be able to reconfigure the pipeline. I'm just wondering if
there are any gotchas to watch out for wrt to garbage collection when not
keeping references. If there are any "best practices" so to speak.

Thanks in advance,
Elvis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://public.kitware.com/pipermail/vtkusers/attachments/20160224/74f8eae2/attachment.html>


More information about the vtkusers mailing list