2

私はちょうど新しい仕事を始めました。ここでは、JNI(C ++ / Javaのブリッジング用)を初めて使用します。私はJNIを初めて使用するので、私の許しを許してください:)

(win32)Javaアプリでは、C++DLLをロードしています。Java側には、「SomeJClass」のインスタンスがいくつかあります。これらの各インスタンスは、DLL側の「SomeCClass」の対応するインスタンスにアクセスする必要があります。DLLは、GlobalDoSomethingInC()などのエントリポイントを公開します。ここでは、Doer :: DoSomethingInC()のインスタンスメソッドを呼び出す必要があります。したがって、それぞれのthis-pointersをマップするためのスムーズな方法が必要です。また、DLLスレッドが、対応するJavaインスタンスに通知する必要がある興味深いものを検出したときにも同じマッピングを行う必要があります。

私はいくつかの解決策を考えることができますが、私はそれらをあまり好きではありません。私の質問は、これよりも良い方法はありますか?

1 JavaはC:GetNewInstance()を呼び出します。これは、実際には新しいCインスタンスへのポインタであるintを返します。Javaはそれをm_myCInstanceに格納します。次に、JavaはGlobalDoSomethingInC()を呼び出し、1a

// DLL global
void GlobalDoSomethingInC()
{
    // retrive this pointer
    //calling back to Java:  
    jobj tmpJ = NewGlobalRef( env, obj );
    Doer* myDoer = <reinterpret_cast>( Doer )tmpJ->GetMyCInstance();
    myDoer->DoSomething();
    DeleteGlobalRef( env, tmpJ );
    // Arrrrgh
}

1bまたは:

    // for **every call** that Java adds a parameter, 
    //which is the stored int:m_myCInstance, and
    Doer* myDoer = <reinterpret_cast>( Doer )instanceParam->DoSomethingInC();
    // Can we do better that this?

2 CからJavaに呼び出す場合、状況はおそらく良く見えます

In the constructor C calls back into Java and stores
the Java instance reference 
    in a member variable. m_myJInstance.
    In all subsequent calls m_myJInstance can be used to call back Java.
    In the destructor we need to call DeleteGlobalRef( env, m_myJInstance );

悪くないと思います。しかし、jobject参照を保存することは本当に安全です。 つまり、GCがオブジェクトを移動するとどうなりますか?

3現在のソリューションは「機能」します。しかし、それはむしろhttp://www.codinghorror.com/blog/に属しています:)

ありがとう

4

2 に答える 2

2

通常、これは環境によって多少異なります。私は、JNI よりもさらに原始的な KNI のみを使用しました。GC を備えているのは 1 つだけである 2 つのシステム間でメモリ追跡を混在させているため、かなりの醜さは避けられないと思います。

一般に、C コードのすべての呼び出しを関数でラップして、厄介なキャストを処理するのが最善であることがわかりました。これは避けられないと思います。(ところで、ここでは Java 以外のコードを意味するために C を使用します)

C 側では、Java オブジェクトの移動は間違いなく潜在的な問題です。プラットフォームによって異なりますが、ライブラリ内にいる限り、Java GC が発生しないと予想できるため、オブジェクトは安定していると思います。これを確認する必要があります。一方、そうでない場合は、かなり失敗しています。その場合、JNI に公開されている関数への逆参照/キャストを分離するのと同じことを実行して、呼び出されたすべての関数で通常の C オブジェクトを問題なく操作できるようにする必要があります。

本当に醜くなるのは、どちらかの側でオブジェクトがスコープ外になる可能性がある場合です。その場合、どちらかの側がオブジェクトへの参照を保持している可能性があるためです。ここでは、Java 側でファイナライザーを使用し、C 側でデストラクタを使用しました。きれいではありませんでしたが、それは仕方のないことだと思います。

簡単に言えば、どちらかの言語での作業の大部分について、そのようなことを心配する必要がないように、2つの言語間のインターフェイスの周りの醜さを分離することは、やや醜いでしょう。

また、このインターフェイス上に存在するオブジェクトの基本クラスを用意することも価値があります。ここでは、いくつかの醜さを分離することもできます。

于 2009-04-28T09:11:28.893 に答える