Difference between revisions of "Slicer3:VTK Leak Debugging"
m (1 revision) |
|||
Line 1: | Line 1: | ||
+ | ==In your code== | ||
+ | |||
If you are getting leaks for a vtkObject but can't figure out where it's coming from, you can try making a change to the constructor for that class and checking the debug output (warning, it can be verbose). What you will see from the following type of change is instances that are created but never destroyed. Then you can add other debug statements in your code and narrow down which instances aren't being deleted. | If you are getting leaks for a vtkObject but can't figure out where it's coming from, you can try making a change to the constructor for that class and checking the debug output (warning, it can be verbose). What you will see from the following type of change is instances that are created but never destroyed. Then you can add other debug statements in your code and narrow down which instances aren't being deleted. | ||
Line 32: | Line 34: | ||
this->Data->UnRegister(this); | this->Data->UnRegister(this); | ||
} | } | ||
+ | </pre> | ||
+ | |||
+ | == In VTK == | ||
+ | |||
+ | In VTK/Common/vtkObjectBase.cxx, modify the RegisterInternal and UnRegisterInternal methods as follows. The prints to cerr will provide a running list of all memory allocation activity. To make this even more useful, you may want to change places in your code (and VTK code) from o->Delete() to o->UnRegister(this). | ||
+ | |||
+ | <pre> | ||
+ | //---------------------------------------------------------------------------- | ||
+ | void vtkObjectBase::RegisterInternal(vtkObjectBase* o, int check) | ||
+ | { | ||
+ | std::cerr << this << " " << this->GetClassName() << " " << this->ReferenceCount << " Register by "; | ||
+ | if ( o ) | ||
+ | { | ||
+ | std::cerr << o->GetClassName(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | std::cerr << "NULL"; | ||
+ | } | ||
+ | std::cerr << "\n"; | ||
+ | |||
+ | // If a reference is available from the garbage collector, use it. | ||
+ | // Otherwise create a new reference by incrementing the reference | ||
+ | // count. | ||
+ | if(!(check && | ||
+ | vtkObjectBaseToGarbageCollectorFriendship::TakeReference(this))) | ||
+ | { | ||
+ | ++this->ReferenceCount; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | //---------------------------------------------------------------------------- | ||
+ | void vtkObjectBase::UnRegisterInternal(vtkObjectBase* o, int check) | ||
+ | { | ||
+ | std::cerr << this << " " << this->GetClassName() << " " << this->ReferenceCount << " Unregister by " | ||
+ | if ( o ) | ||
+ | { | ||
+ | std::cerr << o->GetClassName(); | ||
+ | } | ||
+ | else | ||
+ | { | ||
+ | std::cerr << "NULL"; | ||
+ | } | ||
+ | std::cerr << "\n"; | ||
+ | |||
+ | // If the garbage collector accepts a reference, do not decrement | ||
+ | // the count. | ||
+ | if(check && this->ReferenceCount > 1 && | ||
+ | vtkObjectBaseToGarbageCollectorFriendship::GiveReference(this)) | ||
+ | { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | // Decrement the reference count. | ||
+ | if(--this->ReferenceCount <= 0) | ||
+ | { | ||
+ | // Count has gone to zero. Delete the object. | ||
+ | #ifdef VTK_DEBUG_LEAKS | ||
+ | vtkDebugLeaks::DestructClass(this->GetClassName()); | ||
+ | #endif | ||
+ | delete this; | ||
+ | } | ||
+ | else if(check) | ||
+ | { | ||
+ | // The garbage collector did not accept the reference, but the | ||
+ | // object still exists and is participating in garbage collection. | ||
+ | // This means either that delayed garbage collection is disabled | ||
+ | // or the collector has decided it is time to do a check. | ||
+ | vtkGarbageCollector::Collect(this); | ||
+ | } | ||
+ | } | ||
+ | |||
</pre> | </pre> |
Revision as of 17:35, 5 December 2008
Home < Slicer3:VTK Leak DebuggingIn your code
If you are getting leaks for a vtkObject but can't figure out where it's coming from, you can try making a change to the constructor for that class and checking the debug output (warning, it can be verbose). What you will see from the following type of change is instances that are created but never destroyed. Then you can add other debug statements in your code and narrow down which instances aren't being deleted.
Add this at the beginning of the constructor:
this->DebugOn(); vtkDebugMacro("constructing");
and this in the destructor:
vtkDebugMacro("destructing");
For example, these changes helped me find an extra instance of vtkPoints
// Construct object with an initial data array of type float. vtkPoints::vtkPoints(int dataType) { this->DebugOn(); vtkDebugMacro("constructing"); this->Data = vtkFloatArray::New(); this->Data->Register(this); this->Data->Delete(); this->SetDataType(dataType); this->Data->SetNumberOfComponents(3); this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = 0.0; this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = 1.0; } vtkPoints::~vtkPoints() { vtkDebugMacro("destructing"); this->Data->UnRegister(this); }
In VTK
In VTK/Common/vtkObjectBase.cxx, modify the RegisterInternal and UnRegisterInternal methods as follows. The prints to cerr will provide a running list of all memory allocation activity. To make this even more useful, you may want to change places in your code (and VTK code) from o->Delete() to o->UnRegister(this).
//---------------------------------------------------------------------------- void vtkObjectBase::RegisterInternal(vtkObjectBase* o, int check) { std::cerr << this << " " << this->GetClassName() << " " << this->ReferenceCount << " Register by "; if ( o ) { std::cerr << o->GetClassName(); } else { std::cerr << "NULL"; } std::cerr << "\n"; // If a reference is available from the garbage collector, use it. // Otherwise create a new reference by incrementing the reference // count. if(!(check && vtkObjectBaseToGarbageCollectorFriendship::TakeReference(this))) { ++this->ReferenceCount; } } //---------------------------------------------------------------------------- void vtkObjectBase::UnRegisterInternal(vtkObjectBase* o, int check) { std::cerr << this << " " << this->GetClassName() << " " << this->ReferenceCount << " Unregister by " if ( o ) { std::cerr << o->GetClassName(); } else { std::cerr << "NULL"; } std::cerr << "\n"; // If the garbage collector accepts a reference, do not decrement // the count. if(check && this->ReferenceCount > 1 && vtkObjectBaseToGarbageCollectorFriendship::GiveReference(this)) { return; } // Decrement the reference count. if(--this->ReferenceCount <= 0) { // Count has gone to zero. Delete the object. #ifdef VTK_DEBUG_LEAKS vtkDebugLeaks::DestructClass(this->GetClassName()); #endif delete this; } else if(check) { // The garbage collector did not accept the reference, but the // object still exists and is participating in garbage collection. // This means either that delayed garbage collection is disabled // or the collector has decided it is time to do a check. vtkGarbageCollector::Collect(this); } }