当底层C ++层保存引用时,在swig director包装器中管理Java生命周期的正确方法是什么?

时间:2012-08-30 17:35:18

标签: swig

给出类似

的界面
%feature("director") HeldBase;
%feature("smartptr") HeldBasePtr;   
typedef SmartPtr<HeldBase> HeldBasePtr;  // a minor wrapper around boost::shared_ptr
// Various typemaps that ensure Java-side HeldBase instances are always HeldBasePtr
class HeldBase {
public:
   virtual void doSomething(int) = 0;
}

class Holder {
   void hold(HeldBasePtr hb);
   void release(HeldBasePtr hb);
   void clear();
   void process(int seconds);
}

现在一些代码实现了HeldBase,在java端做了类似的事情:

class MyHeldBase: extends HeldBase { 
   void doSomething(int i) { System.out.println("Hello whirled"); }
}

Holder h = new Holder();
HeldBase local = new MyHeldBase();
h.hold(new MyHeldBase());
h.hold(local);
h.process(1000000);     // presumably doing something with the held things.

底层C ++层“正确”处理智能指针,因此(例如)销毁Holder(swig代理和底层C ++对象)会正确地减少底层智能指针的引用计数。

现在'本地'持有的基础工作正常,但没有在java端的引用的那个给出“null upcall”错误,大概是在一些gc导致java实例消失之后。

我注意到生成的swigTakeOwnership和swigReleaseOwnership方法,并在代码中跟踪它们以切换导演是否持有GlobalRef或GlobalWeakRef。所以我做了一些包装代码,以便调用hold(HeldBase hb)调用hb.swigReleaseOwnership()和release()调用hb.swigTakeOwnership()。看看代码似乎swigReleaseOwnership会将底层导演ref转换为GlobalRef(这样C ++层将拥有Java MyHeldBase的所有权)。反之亦然swigTakeOwnership。

不幸的是,由于无关的原因,这不起作用...我们的字体图中的某些内容使得swigTakeOwnership和swigReleaseOwnership无法调用,因为他们(认为他们)持有HeldBase *而不是HeldBasePtr *。

如果这是解决此问题的正确方法,我将尝试追踪为何没有正确生成这些方法。但我仍然觉得有一些未解决的问题(很难想到。)

例如,如何:

HeldBase local = new MyHeldBase()
Holder h1 = new Holder(); Holder h2 = new Holder(); 
h1.hold(local);
h2.hold(local);
h1.release(local)
local = null;

在这种情况下,对swigReleaseOwnership()的调用会发生两次,但第二次是noop。当release()调用swigTakeOwnership(使引用返回到GlobalWeakRef)时,java层再次“拥有”并且h2将获得null upcall。此外,如果需要调用swigTakeOwnership,那么Holder.clear()似乎意味着我需要添加代码来保存所有传递的java扩展控制器(此时我可以这样做来管理它们的生命周期)。

当使用带有导向器的智能指针时,“感觉”就好了,导演的C ++端应该总是只使用GlobalRef并且事情将“正常工作”但OTOH似乎是内存泄漏,因为那时C ++方面将保持Java代理生存,反之亦然。

0 个答案:

没有答案