Unnoticeable memory leaks. Part 2


As there are multiple objects referencing each other there is no single one to check a reference count of. So I had to choose a slightly different approach which you can reuse in your cases. I have created Standard_Transient* pointers to the objects I wanted to track counts of. Using Handles is non-applicable as assignment increases a ref count and therefore prevents destroying objects. To enforce destruction the handle objects are simply put inside the scope. Here is a code snippet:

Standard_Transient *apWS, *apModel, *apTR, *apTP, *apTW, *apFP, *apG;
IGESCAFControl_Reader aReader;
apWS = aReader.WS().Access();
apModel = (aReader.WS()->Model()).Access();
apTR = (aReader.WS()->TransferReader()).Access();
apTP = (aReader.WS()->TransferReader()->TransientProcess()).Access();
apTW = (aReader.WS()->TransferWriter()).Access();
apFP = (aReader.WS()->TransferWriter()->FinderProcess()).Access();
apG = (aReader.WS()->HGraph()).Access();

The objects' counters while within the scope ranged from 1 to 8 confirming they have been significantly reused inside the Data Exchange framework. When exiting the scope the cascade of objects is destroyed nullifying most references except one – of IGESData_IGESModel, the object that represents a graph of the IGES entities in memory.

This proved suspicions that memory is not fully cleaned upon reading of an IGES file. That is, once you have read an IGES file and started using 3D models contained in it, memory still contains a lot of unused information. Unnoticed memory leak.

Experimenting further I have found a root-cause which was in an extra handle to the IGES model inside the IGESToBRep_Actor class which itself always remained in the IGESControl_Controller which was supposed to reside in memory for the life cycle of the app (it's a registered in a global container). Allocated memory is freed upon next IGES file import and this repeats over and over again.

So, as a work-around I had to add the following line after the IGES file has been read.

Handle(IGESToBRep_Actor)::DownCast (aReader.WS()->TransferReader()->Actor())->SetModel (new IGESData_IGESModel);

Note that specifying a null model is impossible since IGESToBRep_Actor::SetModel() tries to access it assuming its non-null. You may want to add the above line to your code reading IGES.

Fortunately, similar checks in IGES export revealed that no memory is left orphaned. I only checked objects similar to those used in testing IGES import, not sure if there are no any tiny orphans.

Hope these findings will be useful for you and that you can check your code in critical places to make sure you do not produce memory leaks. Good luck !


P.S. I used the autoexp.dat for Microsoft Visual Studio debugger to facilitate display of the Open CASCADE handles. This was described in an earlier post.

No comments:

Post a Comment