次のようなインターフェースが与えられた場合
%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++ レイヤーはスマート ポインターを「適切に」処理するため、(たとえば) ホルダー (swig プロキシと基礎となる C++ オブジェクト) を破棄すると、基礎となるスマート ポインターの参照カウントが正しく減少します。
現在、「ローカル」に保持されているベースは正常に動作しますが、Java 側に保持されている参照を持たないベースは、おそらく一部の gc によって Java インスタンスが消えた後、「null upcall」エラーを返します。
生成された swigTakeOwnership および swigReleaseOwnership メソッドに気付き、コード内でそれらを追跡して、ディレクターが GlobalRef または GlobalWeakRef を保持しているかどうかを切り替えました。そこで、hb.swigReleaseOwnership() を hold(HeldBase hb) への呼び出しと hb.swigTakeOwnership() を呼び出す release() を呼び出すように、いくつかのラッパー コードを作成しました。コードを見ると、swigReleaseOwnership は基になるディレクター ref を GlobalRef に変換するように見えました (C++ レイヤーが Java MyHeldBase の所有権を保持するように)。swigTakeOwnership の場合はその逆です。
残念ながら、これは別の理由で機能しませんでした... typemap の何かが swigTakeOwnership と swigReleaseOwnership を呼び出し不能にしました。
それがこの問題を解決する正しい方法である場合、これらのメソッドが正しく生成されない理由を突き止めようとします。しかし、まだ解決されていない問題 (考えにくい) があるように感じます。
たとえば、次のようになります。
HeldBase local = new MyHeldBase()
Holder h1 = new Holder(); Holder h2 = new Holder();
h1.hold(local);
h2.hold(local);
h1.release(local)
local = null;
この場合、swigReleaseOwnership() への呼び出しは 2 回発生しますが、2 回目は noop です。release() が swigTakeOwnership を呼び出す (参照を GlobalWeakRef に戻す) と、Java レイヤーは再び「所有」し、h2 は null アップコールを取得します。また、swigTakeOwnership の呼び出しが必要な場合、Holder.clear() は、渡されたすべての Java 拡張ディレクターを保持するコードを追加する必要があることを意味しているようです (その時点で、ライフサイクルを管理するためにそれを行うことができます)。
ディレクターでスマートポインターを使用する場合、ディレクターのC++側は常にGlobalRefを使用する必要があり、物事は「うまくいく」ように「感じます」が、OTOHはC++側がJavaを保持するため、そこにメモリリークがあるようですプロキシは生きており、その逆も同様です。