I made some more tests to try to understand memory problems described.
Destructors into the OC wrapper code (called when Dispose() method is used
into C# application) have two different type of solution:
1) Delete of nativeHandle only like this:
~OCTopoDS_Shape()
{
delete nativeHandle;
}
2) Call Nullify on nativeHandle and then delete nativeHandle like this:
~OCGeom_TrimmedCurve()
{
nativeHandle->Nullify();
delete nativeHandle;
}
First of all i cannot understand when Nullify should be used. I suppose
that
OCC transient class can be deallocated automatically by OCC memory
management strategy based on smart pointer and reference counters
even if Nullify is not called.
Second, after delete, nativeHandle is not assigned to a null value, so in
a case, for example, an OCGeom_TrimmedCurve is deleted, more than one
destructor is called by the system:
~OCGeom_TrimmedCurve(), ~OCGeom_BoundedCurve() from which
OCGeom_TrimmedCurve() is derived and so on, up to the base class ....
All these desctructor call a delete on the same nativeHandle pointer and
more a Nullify().
I suppose that this could be the cause of the crash I see when I call
Dispose() on a OCWrapper class into my C# application.
So I have modified all OC Wrapper destructor in the following way:
~classeName
{
if (nativeHandle != 0)
{
delete nativeHandle;
nativeHandle = 0;
}
}
This modification solve the crash problems I described. In the sample
application i mentioned before, i see that i can call Dispose() without
any crash and furthemore I noticed that in a cycle like the following one
memory does't increase:
for (n = 0; n < 1000; n++)
{
OCBRepPrimAPI_MakeBox b1 = new OCBRepPrimAPI_MakeBox(100.0, 200.0,
300.0);
OCTopoDS_Shape sh = b1.Shape();
b1.Dispose();
sh.Dispose();
}
Unfortunately, in the second case below I noticed no crashes but the
memory
still increase and is never deallocated.
OCgp_Pnt p1 = new OCgp_Pnt(10, 15, 20);
OCgp_Pnt p2 = new OCgp_Pnt(30, 40, 50);
for (n = 0; n < 1000; n++)
{
OCGC_MakeSegment mkSegment = new OCGC_MakeSegment(p1, p2);
if (mkSegment.IsDone() == true)
{
OCGeom_TrimmedCurve segmentToWrite = mkSegment.Value();
segmentToWrite.Dispose();
}
mkSegment.Dispose();
}
With some more test I found that not all OCC classes provide virtual
destructor.
This could be the cause of the problem of memory increasing noticed in a
cycle like this
OCgp_Pnt p1 = new OCgp_Pnt(10, 15, 20);
OCgp_Pnt p2 = new OCgp_Pnt(30, 40, 50);
for (n = 0; n < 1000; n++)
{
OCGC_MakeSegment mkSegment = new OCGC_MakeSegment(p1, p2);
if (mkSegment.IsDone() == true)
{
OCGeom_TrimmedCurve segmentToWrite = mkSegment.Value();
segmentToWrite.Dispose();
}
mkSegment.Dispose();
}
Here, OCGC_MakeSegment uses a nativeHandle on type GC_Root *.
This class hasn't a virtual destructor into OCC so when OC wrapper
in the ~OCGC_MakeSegment call delete nativeHandle, the destructor
of the base class GC_Root is called and not the destructor of
GC_MakeSegment derived class as should be. I think that this problem
can be solved by using an explicit cast when calling delete like this:
delete ((GC_MakeSegment*)nativeHandle);
instead of
delete nativeHandle;
I saw that at least in the case of my example this kind of delete call
solve the problem of memory increasing.
I would like to ask to the OC wrapper developers what they think about
these notes. If the solution that a I found and tested on a specific case
may be valid in general, I ask if it would be possible to take them into
account in the wrapper generator code in order to create destructors
that provide check against 0 (nullptr) and cast as I described above.
What do you think about?