给定一个类似的接口
%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 似乎会将底层的 director 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 将获得空调用。此外,如果需要调用 swigTakeOwnership,那么 Holder.clear() 似乎意味着我需要添加代码来保存所有传递的 java 扩展导向器(此时我可以这样做来管理它们的生命周期)。
它“感觉”就像在将智能指针与导向器一起使用时,导向器的 C++ 端应该始终只使用 GlobalRef 并且事情会“正常工作”但是 OTOH 似乎是那里的内存泄漏,从那时起 C++ 端将保留 Java代理活着,反之亦然。