Slicer3:Memory Management
This page discusses strategies writing and debugging code in Slicer3 such that you avoid memory leaks and double deletes.
Contents
What is a memory leak?
Memory leaks occur when a section of code allocates a block of memory that is never reclaimed.
void MyFunction() { short *buffer = new short[1000]; // this memory is leaked! }
How does memory get deleted multiple times?
A frequent problem with passing pointers from routine to routine is that it becomes very easy to loose track of which routine is responsible for deleting the block of memory. APIs rely on their documentation to educate the developers as to whether the developer is responsible for deleting the memory.
short *buffer = mykit::CreateBuffer(1000); ... myKit::CleanUp(); ... delete [] buffer; // did myKit::CleanUp() already delete this memory?
Reference Counting
VTK and ITK both use reference counting to keep track of outstanding references to an object and automatically delete an object when it is no longer needed. VTK does with via calls to New()/Delete() and Register()/UnRegister() to increase and decrease the number of references to an object. If a function call returns a pointer to an object, the caller can choose to keep a long term handle to that object by increasing the reference count. The caller is responsible for decreasing the reference count when they no longer need the object.
MyClass::Function1() { this->SomeObject = MyOtherClass::GetObject(); this->SomeObject->Register( this ); } MyClass::~MyClass() { if (this->SomeObject) { this->SomeObject->UnRegister(); this->SomeObject = 0; } }
Stack-based coding
One way to avoid memory leaks is to avoid allocating objects on the heap. The Standard Template Library (STL) promotes which type of coding. To use STL safely, all objects stored in STL containers should default constructible and have proper copy constructors, etc.
std::vector<MyObject> vec, anotherVec; vec = myKit::GetObjectList(); // this is a (deep) copy of the vector anotherVec = vec; // this is another deep copy of the vector
When the above vectors go out of scope, the destructor of the vector calls the destructor of each object it contains. If these vectors are vectors to pointers to objects, the destructors of each object are not called.
MyObject::Function() { std::vector<MyObject*> vec; vec.push_back( ); } // destructors are not called on items pointed to by elements of the vectorSmartPointers