Hi, Frank: I am not sure, but I think you could implement your utility function using a python closure. This would allow the original object to remain in scope until the nested function has completed. so for example:
To do closures in python, you have to use lamda, which creates a new function having access to the outer scope, even after the function returns. So def MakeEdge(p1, p2): gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)] mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2) return mkedge.Shape() Becomes: def MakeEdge(p1,p2): gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)] mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2) return lambda e: mkedge.Shape(); now you can do me = MakeEdge(p1,p2); me.Shape() //return the generated shape me.Shape() //return the generated shap again. It will be the same object because the underlying brepbuilder is still in a closure Now if you kill me, the closure will be discarded. Dont know if this helps any or not. On Tue, Mar 16, 2010 at 7:53 PM, Frank Conradie <fr...@qfin.net> wrote: > Hi Thomas > > After much investigation today, I have now added a flag to GarbageCollecter > to disable it for our use, as it really does not work as intended for > relatively complex code (I now manually track which objects I create and > need to call _kill_pointed for). There are two main issues that we run into > with the current GarbageCollector: > > 1. As already discussed, classes like the BRepPrimAPI and BRepAlgoAPI have > an internal "myShape" data member that gets destroyed when the parent > object's _kill_pointed method is called, causing all kinds of issues. As an > example, it makes utility functions like the one below unusable, as the > local BRepPrimAPI object goes out of scope and is thus collected by > GarbageCollector for purging, even though the caller of the function may > want to use the resulting shape for some time to come, after the parent is > "purged": > > def MakeEdge(p1, p2): > gp1,gp2 = [gp_Pnt(x,y,z) for x,y,z in (p1,p2)] > mkedge = BRepBuilderAPI_MakeEdge(gp1, gp2) > return mkedge.Shape() > > 2. Every time a C++ OCC object is retrieved from Python in any way, a brand > new SWIG wrapper object is instantiated for it, very easily/quickly leading > to multiple wrapper objects on the Python side for the same underlying C++ > object (I see this especially when using OCC shape containers repeatedly). > When any one of these wrapper objects goes out of scope and is collected and > purged, the underlying C++ object is destroyed (via _kill_pointed), even > though there may well be other Python wrapper objects still needing access > to it. > I guess the ideal solution to this issue would be to keep a mapping of > C++ object -> SWIG wrapper object on the C++ side, so that there is always a > 1-to-1 correspondence between the two, but I'm not sure how plausible this > really is from an implementation point-of-view. As an example of what I > mean, consider this: every time you call "mkedge.Shape()" in my example > above, you get a new/different Python object, wrapping the same underlying > myShape instance, which is totally unexpected and unintuitive from a Python > perspective. A "pure" Python programmer would expect to get the exact same > Python object back every time, and not different wrapper objects with just > an "artificial" identical hash value. > > I realize that this is a very difficult issue, and that as users of the > PythonOCC wrapper library we will need to take responsibility for memory > management issues, but I can see lots of confusion for Python programmers > using the library and expecting "Python-like" behaviour out of the box. > > I wish I new more about the SWIG wrapper object instantiation process so > that I could make more concrete suggestions, instead of just complaining > ;-) What is your gut-feeling about this Thomas - do you think these two > issues can be addressed in the wrapper, or is the current way the only > viable implementation? If you can give me a short description of the SWIG > wrapper instantiation process, I may be able to delve into it myself. > > Thanks for your help with this thus far, > Frank > > > > > On 16/03/2010 9:04 AM, Thomas Paviot wrote: > > Hi Frank, > > I also suggest you use the push_context() and pop_context() methods at > the beginning and the end of your algorithm. garbage.push_context() creates > a new collector. Objects collected will go to this new list. Then, at the > end of your algorithm, just call .smart_purge() and then pop_context(). > Otherwise, when calling the smart_purge() method, you'll erase all other > objects that might have been stored in the gc thus causing strange things. > > def my_high_memory_consuming_algorithm(): > GarbageCollector.garbage.push_context() > > ... do whatever you want ... > > GarbageCollector.garbage.smart_purge() #only the objects created > since the call to push_context are erased. Use MMGT_OPT=0 to make sure > freeing #memory. > GarbageCollector.pop_context() > return data > > There's also a garbage.prevent_object(object) method, that will take care > to not delete an object that it's important to keep reference. > > These three functions are quite new (but validated with a unittest). I'm > curious to have your feedback! > > Regards, > > Thomas > > These two functions are quite new, > 2010/3/16 Frank Conradie <fr...@qfin.net> > >> Hi Thomas >> >> Well, I'm glad it's not a bug then! I can think of a few ways to handle >> this situation in my algorithm, so it should not be a problem. I'm just >> wondering how many other classes behave in this "unexpected" way :O >> >> Cheers, >> Frank >> >> >> On 15/03/2010 10:26 PM, Thomas Paviot wrote: >> >> Hi Frank, >> >> This behaviour does not come from SWIG but from OpenCASCADE itself. Let >> me explain you in a few words what happens here. >> >> The BRepPrimAPI_MakeBox class inherits from the BRepBuilderAPI_MakeShape >> one. This class provides the Shape() method you can find in >> BRepPrimAPI_Make* basic geometry constructors. If you have a look at the >> Shape() method in the file BRepBuilderAPI_MakeShape.cxx, you will read: >> >> """ >> >> //======================================================================= >> //function : Shape >> //purpose : >> //======================================================================= >> >> const TopoDS_Shape& BRepBuilderAPI_MakeShape::Shape() const >> { >> if (!IsDone()) { >> // the following is const cast away >> ((BRepBuilderAPI_MakeShape*) (void*) this)->Build(); >> Check(); >> } >> return myShape; >> } >> """ >> >> The Shape() method then returns a reference to the protected attribute >> 'myShape' of the class BRepBuilderAPI_MakeBox. In other words, if you delete >> the BRepPrimAPI_MakeBox instance, you loose the reference to the shape. >> >> For instance: >> >> >>> from OCC.BRepPrimAPI_MakeBox import * >> >>> from OCC.TopoDS import * >> >>> box = BRepPrimAPI_MakeBox(10,10,10) >> >>> shp = box.Shape() >> >>> print shp.IsNull() >> 0 >> >>> del box #object is garbage collected, not deleted yet >> >>> print shp.IsNull() >> 0 >> >>> GarbageCollector.garbage.smart_purge() # all objects are deleted, >> loose the reference to myShape attribute >> >>> print shp.IsNull() >> 1 >> >> Then force objects deletion only if you're sure you don't need the >> shapes anymore. I don't know what you're trying to do exactly, so it's >> difficult to suggest any best practice. >> >> Regards, >> >> Thomas >> >> 2010/3/15 Frank Conradie <fr...@qfin.net> >> >>> Hi Thomas >>> >>> I am getting crash behaviour in the interim 0.5 PythonOCC release, >>> related to the new GarbageCollector implementation. The code below >>> crashes on my PC: >>> >>> ---------------------------------------- >>> from OCC.gp import * >>> from OCC.BRepPrimAPI import * >>> from OCC.BRepBuilderAPI import * >>> from OCC.TopExp import * >>> from OCC.TopoDS import * >>> >>> o = 0.0 >>> w = 0.1 >>> fp1 = (o,o,o) >>> fp2 = (w,w,w) >>> >>> mkbox = BRepPrimAPI_MakeBox(gp_Pnt(fp1[0],fp1[1],fp1[2]), >>> gp_Pnt(fp2[0],fp2[1],fp2[2])) >>> s = mkbox.Shape() >>> del mkbox >>> >>> print s.ShapeType() >>> GarbageCollector.garbage.smart_purge() >>> # The next line crashes my system >>> print s.ShapeType() >>> ---------------------------------------- >>> >>> It is almost as if calling _kill_pointed for the mkbox causes shape "s" >>> to become "corrupted" in some way. I dug through the SWIG code a bit, >>> but cannot see anything obviously wrong, so I was hoping you could shed >>> some light on the issue. >>> >>> By the way, I did get the SVN compiled myself as well, and get the same >>> crash with my compiled lib as well as the one you made available on your >>> website. >>> >>> Thanks, >>> Frank >>> >>> >>> _______________________________________________ >>> Pythonocc-users mailing list >>> Pythonocc-users@gna.org >>> https://mail.gna.org/listinfo/pythonocc-users >>> >> >> >> _______________________________________________ >> Pythonocc-users mailing >> listpythonocc-us...@gna.orghttps://mail.gna.org/listinfo/pythonocc-users >> >> >> _______________________________________________ >> Pythonocc-users mailing list >> Pythonocc-users@gna.org >> https://mail.gna.org/listinfo/pythonocc-users >> >> > > _______________________________________________ > Pythonocc-users mailing > listpythonocc-us...@gna.orghttps://mail.gna.org/listinfo/pythonocc-users > > > _______________________________________________ > Pythonocc-users mailing list > Pythonocc-users@gna.org > https://mail.gna.org/listinfo/pythonocc-users > >
_______________________________________________ Pythonocc-users mailing list Pythonocc-users@gna.org https://mail.gna.org/listinfo/pythonocc-users