Free image memory

Hi,

I am working with very big images (> 5GB) and running out of memory. I’d like to know how I should free the memory used by an image that I’ve read, after I no longer need it.
My code looks like this:

typedef itk::Image<unsigned char,3> ImageType;
ImageType::Pointer imskel;

typedef itk::ImageFileReader<ImageType> FileReaderType;

// Read skeleton file
FileReaderType::Pointer readerskel = FileReaderType::New();
readerskel->SetFileName(skelFile);
try
{
	printf("Reading input skeleton file: %s\n",skelFile);
	readerskel->Update();
}
catch (itk::ExceptionObject &e)
{
	std::cout << e << std::endl;
	fprintf(fperr,"Read error on skeleton file\n");
	fclose(fperr);
	return 2;	// Read error on input file
}
imskel = readerskel->GetOutput();

pskel = (unsigned char *)(imskel->GetBufferPointer());

I work with pskel.

Thanks
Gib

ITK’s pipeline features streaming support, which is the ability to request a sub-region and only provide that sub-region. Algorithms can be witting which iteratively process these sub-regions or chunks one at a time.

There is a section in the ITK Software Guide about how to write a streaming filter:
https://itk.org/ITKSoftwareGuide/html/Book1/ITKSoftwareGuide-Book1ch8.html#x47-1350008.3

I doubt you can have your image like that. When readerskel and imskel go out of scope, the image will be deleted. So in addition to keeping pskel you should also keep an image smart pointer (imskel), and delete that when you need the memory freed. A simple way to delete the image is imskel = ImageType::New();, which assigns a new image which does not have its buffer allocated to imskel smart pointer, which in turn deletes the last reference to the old image so it is deleted and its buffer is freed.

Edit: even better way to delete is imskel = nullptr;

Thanks for the responses. Dzenan, both imskel and pskel are global variables and pskel is used in many places. readerskel is not global, so it goes out of scope, but that apparently causes no problems.
I’ll try your suggestion of imskel = nullptr.

The streaming filter option looks interesting, Bradley, but it might be non-trivial to fit it into the way my program works.

Best regards
Gib

Unfortunately, on Windows neither method of freeing image memory works (for me). On Linux assigning a new image doesn’t work, and “nullptr is not declared in this scope”. I gather it may be possible to jump through some hoops to make nullptr declared, but since it doesn’t have effect on Windows it doesn’t seem worth the effort.

Any other suggestions?

If that doesn’t free your image, you might have more references to it. Can you print it std::cout<<imskel; to see its reference count? If you want to force-free it, you might do something like:

imskel->GetPixelContainer()->SetImportPointer(NULL, 0);

Here is what std::cout<<imskel produces:

Image (0000000001F69680)
RTTI typeinfo: class itk::Image<unsigned char,3>
Reference Count: 3
Modified Time: 189
Debug: Off
Object Name:
Observers:
none
Source: (0000000001C7F900)
Source output name: Primary
Release Data: Off
Data Released: False
Global Release Data: Off
PipelineMTime: 49
UpdateMTime: 190
RealTimeStamp: 0 seconds
LargestPossibleRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [3219, 1820, 929]
BufferedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [3219, 1820, 929]
RequestedRegion:
Dimension: 3
Index: [0, 0, 0]
Size: [3219, 1820, 929]
Spacing: [1, 1, 1]
Origin: [0, 0, 0]
Direction:
1 0 0
0 1 0
0 0 1

IndexToPointMatrix:
1 0 0
0 1 0
0 0 1

PointToIndexMatrix:
1 0 0
0 1 0
0 0 1

Inverse Direction:
1 0 0
0 1 0
0 0 1

PixelContainer:
ImportImageContainer (0000000001F12E50)
RTTI typeinfo: class itk::ImportImageContainer<unsigned __int64,unsigned
char>
Reference Count: 1
Modified Time: 187
Debug: Off
Object Name:
Observers:
none
Pointer: 000000013F900040
Container manages memory: true
Size: 5442620820
Capacity: 5442620820

You probably have some other smart pointers to that image then. You can forcefully reduce the reference count by imskel->UnRegister();, but that might cause a crash in your program because you will probably have some dangling pointers once your image has been deallocated.

Hi Dzenan,

Here are all the code lines that mention imskel:

ImageType::Pointer im, imskel;

imskel = readerskel->GetOutput();

width = imskel->GetLargestPossibleRegion().GetSize()[0];

height = imskel->GetLargestPossibleRegion().GetSize()[1];

depth = imskel->GetLargestPossibleRegion().GetSize()[2];

pskel = (unsigned char *)(imskel->GetBufferPointer());

Can you see how there are 3 references? Maybe pskel needs to be freed first.

Thanks

Gib

I don’t think GetBufferPointer() causes additional references. You can check that by printing imskel before and after assigning pskel. But remember that readerskel has one reference to the image. You should examine reference count outside of the function (or at least block) which creates the reader. Something like:

{
ReaderType::Pointer reader=ReaderType::New();
...
imskel = reader->GetOutput();
imskel->DisconnectPipeline();
} //closing block destructs the reader and should reduce reference count
std::cout<<imskel; //check reference count

I printed imskel in a function after the last usage of pskel (the code I showed is in main.) readerskel is local to main, but imskel and pskel are global in scope.
I will run the more extensive tests you’ve suggested later.

I have run some tests. Putting readerskel in a block has the effect of reducing the number of references from 3 to 2, and allows either method (setting imskel to nullptr or ImageType::New()) to free the memory. This is unaffected by assigning pskel to point to the image buffer, and also unaffected by imskel->DisconnectPipeline();

This is success!

Thanks!

1 Like

Are you holding onto the filter that generated the image?

If I understand your question, the image is generated by the reader, e.g.:

typedef itk::ImageFileReader ImageReaderType;

{

    ImageReaderType::Pointer reader = ImageReaderType::New();

    reader->SetFileName(infile);

    reader->Update();

    im = reader->GetOutput();

}