2009-04-28 11 views
2

私は新しい仕事を始めました。ここでは、JNI(C++/Javaのブリッジ用)を使用することに新しいことがあります。私はJNIを初めて利用していますので、私のnoobnessを許してください:)JNIとC++のオブジェクトインスタンス

私たちの(win32)Javaアプリケーションでは、C++ DLLをロードしています。 Java側では、「SomeJClass」のいくつかのインスタンスがあります。これらの各インスタンスは、DLL側の「SomeCClass」の対応するインスタンスにアクセスする必要があります。 DLLは、GlobalDoSomethingInC()などのエントリポイントを公開します。ここでは、Doer :: DoSomethingInC()のインスタンスメソッドを呼び出す必要があります。だから私は、それぞれのthis-pointerをマップするためのスムーズな方法が必要です。 また、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のか:CからJavaへの呼び出しについて

// 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、物事があまりにも

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/にかなりの属する:)

ありがとう

答えて

2

通常、これはややお使いの環境に依存します。私はKNIだけを使用しています.KNIはJNIよりも原始的です。私は2つのシステム間でメモリトラッキングを混在させているので、醜さはかなり避けられないと思います。そのうちの1つだけにGCがあります。

一般的に、私は避けられないと思う厄介なキャスティングの世話をした関数で、Cコードからすべての呼び出しをラップするのが最も良いことを発見しました。 (ここでは、Cを使用して非Javaコードを意味します)

Javaオブジェクトの移動は、潜在的な問題です。それはあなたのプラットフォームに依存しますが、あなたがlib内にいる限り、Java GCが発生しないと期待できるので、オブジェクトは安定しています。あなたはこれを知る必要があります。一方で、そうでない場合、あなたはかなり嫌になります。その場合、JNIに公開されている関数に参照解除/キャストを分離することと同じことをしたいので、呼び出されたすべての関数の通常のCオブジェクトをうまく処理できます。

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

2つの言語間のインターフェースの醜さを少し醜いものにします。その結果、どちらの言語でも、そのようなことを心配する必要はありません。

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

0

jobjectは、オブジェクトに対する不透明なハンドルです。ランタイム実装(Android 2.x vs 4.xを参照)では異なるかもしれませんが、それが不透明なオブジェクトであると信じてください。

現在の解決策はおそらく正しいでしょう。 NewGlobalRefを呼び出すと、オブジェクトのrefcountが増加し、DeleteGlobalRefを呼び出すまで処理されません(そして、GCは到達不能であることに気づきました) )

関連する問題