Documentation/4.3/Developers/Tutorials/MemoryManagement

From Slicer Wiki
Revision as of 03:34, 5 September 2013 by UpdateBot (talk | contribs) (Nightly -> 4.3)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Documentation < 4.3 < Developers < Tutorials < MemoryManagement


For the latest Slicer documentation, visit the read-the-docs.


From http://massmail.spl.harvard.edu/public-archives/slicer-devel/2011/007513.html

Like VTK, Slicer contains some "factory" methods:

- vtkMRMLScene::CreateNodeByClass()
- vtkMRMLScene::GetNodesByClass()
- ...

Like in C++, it means that the functions return an object with a reference count of 1 that nobody "owns" and the caller must take care of releasing the object to avoid memory leak.

While there is workaround for some methods ( slicer.mrmlScene.CreateNodeByClass('vtkMRMLModelNode') should be replaced by slicer.vtkMRMLModelNode() ) there is currently no automatic/clean mechanism to release the object created by such methods.

The only "hack" that exists for now is to decrease the reference count manually in your code:

nodes = slicer.mrmlScene.GetNodesByClass('vtkMRMLLinearTransformNode')
nodes.UnRegister(slicer.mrmlScene)      # ----> (reference count was 2, keep 1 for the python reference)
...

In C++, the following would apply:

vtkCollection* nodes =
mrmlScene->GetNodesByClass("vtkMRMLLinearTransformNode");
...
nodes->Delete();

or using vtkSmartPointer:

vtkSmartPointer<vtkCollection> nodes;
nodes.TakeReference(mrmlScene->GetNodesByClass("vtkMRMLLinearTransformNode"));
...

Amendment from JC http://viewvc.slicer.org/viewvc.cgi/Slicer4?view=revision&revision=19772

The reference count shouldn't be decreased using the naive approach where it is set to one. Indeed, internally, the reference count could be any number greater than one. It doesn't have to be 2.

Considering this last remark, using the following approach is *REQUIRED*, otherwise it will lead to a CRASH of the application.

n = slicer.mrmlScene.CreateNodeByClass('vtkMRMLViewNode')
slicer.mrmlScene.addNode(n)
n.UnRegister(slicer.mrmlScene)

Even better, this specific example can be simplified using the following syntax, this is the *RECOMMENDED* approach, it will prevent bug, memory leaks and crashes:

 n = slicer.mrmlScene.addNode(slicer.vtkMRMLViewNode())

And if the name of the node is generated at runtime, this could be done:

 n = eval('slicer.mrmlScene.AddNode(slicer.%s())' % 'vtkMRMLViewNode')