Page MenuHomePhabricator

Memory leak when using mitk::Image::GetVtkImageData
Closed, DuplicatePublic

Description

In mitkImage.h the method "ImageVtkAccessor* GetVtkImageData(int t = 0, int n = 0);" produces a memory leak.

Code to reproduce this:

for (int i=0; i<10; i++)
{

// Normal way to load an image
QString stringImage("c:/image.nrrd");
mitk::DataNode::Pointer nodeImage = CommonFunctionality::FileOpen( stringImage );   
mitk::Image::Pointer image = dynamic_cast<mitk::Image*>(nodeImage->GetData());   

// This function allocates memory and never releases it, even if the mitkImage is already destroyed
image->GetVtkImageData()

}

The cause is here:
in the function "mitk::ImageVtkAccessor* mitk::Image::GetVtkImageData(int t, int n)" there is a line
ImageDataItemPointer volume=GetVolumeData(t, n);
This creates an itk Smartpointer object called "volume" which points to a specific volume of the image. This volume object is created, but never deleted. At this time, the object "volume" is not very big. But some lines later there is a call
volume->GetVtkImageData(this).
This call causes the "volume" object to fill it's m_VtkImageData pointer with a lot of image data. "volume" would delete and free that memory in it's destructor. But the destructor of "volume" is never called. I am not sure why... Seems like the Itk Smartpointer is not working properly or there are cross-references which prevents the deletion.

Any ideas?

Event Timeline

"GetVtkImageData" is called by a number of filters. e.g. ExtractSliceFilter. At the moment this memory leak makes it impossible to use these filters in an autonomous processing, where more than 6-7 images are handled.

Could you extend the image test to show the false behaviour? Maybe verify in the test that DeleteEvent is fired? That would probably make it easier to fix.

The Reproduction code was incorrect. You need to load the image as Datanode and then cast it to an image to reproduce it. The memory leak is propably casue by smartpointer dependencies. here some code examples:

// No memory leak
mitk::Image::Pointer image;
mitk::DataNode nodeImage;
for (int i=0; i<100; i++)
{

QString filestring = fileList.at(i);
nodeImage = CommonFunctionality::FileOpen( filestring ); 
image = dynamic_cast<mitk::Image*>(nodeImage->GetData()); 
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 2

}

// memory leak!
mitk::Image::Pointer image;
mitk::DataNode nodeImage;
for (int i=0; i<100; i++)
{

QString filestring = fileList.at(i);
nodeImage = CommonFunctionality::FileOpen( filestring ); 
image = dynamic_cast<mitk::Image*>(nodeImage->GetData()); 
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 2
image->GetVtkdata();
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 3

}

// no memory leak
mitk::Image::Pointer image;
mitk::DataNode nodeImage;
for (int i=0; i<100; i++)
{

QString filestring = fileList.at(i);
nodeImage = CommonFunctionality::FileOpen( filestring ); 
image = dynamic_cast<mitk::Image*>(nodeImage->GetData()); 
image = image->Clone();
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 1
image->GetVtkdata();
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 1

}

Two more interesting examples:

// No memory leak
mitk::Image::Pointer image;
mitk::DataNode nodeImage;
for (int i=0; i<100; i++)
{

QString filestring = fileList.at(i);
nodeImage = CommonFunctionality::FileOpen( filestring ); 
image = dynamic_cast<mitk::Image*>(nodeImage->GetData()); 
nodeImage = NULL;
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 1

}

// memory leak
mitk::Image::Pointer image;
mitk::DataNode nodeImage;
for (int i=0; i<100; i++)
{

QString filestring = fileList.at(i);
nodeImage = CommonFunctionality::FileOpen( filestring ); 
image = dynamic_cast<mitk::Image*>(nodeImage->GetData()); 
nodeImage = NULL;
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 1
image->GetVtkdata();
MITK_INFO << "Image Ref:" << image->GetExternalReferenceCount(); // 2

}

A workaround would be cloning of the image before calling getVtkData. I'm gonna investigate the source of the problem some other time.

Bug will be fixed with the cahnges from T13953