0

しばらくの間、NDK 側で java.nio.ByteBuffers を使用してきました - Android と JNI、GC、および ICS の将来との関係に関するこの記事に気づきました。ここの記事http://android-developers.blogspot.com/2011/11/jni-local-reference-changes-in-ics.html

だから...ここに懸念があります:

JNI が提供する「ポインター」は、実際には JNI 内部で管理される参照であるように見えるため、渡される前に JNI メソッドで NewGlobalReference() としてマークされていない場合、ある時点で GC によって「移動」または削除される可能性があります。 C++ クラスに?

私の JNI メソッドでは、ダイレクト バッファ アドレスを取得し、それを使用するクラスに渡します。

env->NewGlobalRef(jobject); 
env->NewLocalRef(jobject); 
env->DeleteGlobalRef(jobject); 

管理。

今のところすべて動作しますが、正しいですか?

考え?

PS - C++ の終了/デストラクタで free(ByteBuffer) を使用します

4

2 に答える 2

2

ローカル参照は、それが渡された、または作成された JNI メソッドの間のみ有効です。そのメソッドが JVM に戻ると、参照は無効になります。そのルールを破っていなければ、問題ありません。

于 2013-06-25T21:43:15.877 に答える
0

おっしゃっていることが少しわかりにくいので、いくつかの点を明確にしておきましょう。

jobjectJNI 呼び出しから返されるかFindClass、引数 ( jobjectjclass、など) として渡されるかに関係なく、JNI で取得する型はすべてjbyteArrayローカル参照です。それは非常に短い寿命を持っています。これを に渡すとNewGlobalRef、代わりにグローバル参照が返されます。これは、削除するまで続きます。

ポインター型を受け取ったり返したりする JNI 関数は、何かがそれを無効にするまで有効なポインターを提供します。たとえば、 を呼び出すと、 を呼び出すまで有効なGetStringUTFCharsが得られます。const char*ReleaseStringUTFChars

参照はポインターではなく、ポインターは参照ではありません。char*toを渡すことはNewGlobalRefできず、グローバル参照を逆参照することもできません (「できない」とは通常、エラーまたはネイティブ クラッシュです)。

あなたがしていることは、ダイレクトバイトバッファの開始点を指すa を返すオブジェクトを呼び出しGetDirectByteBufferAddressていることです。このポインターは、ストレージが解放されるまで有効です。それがどのように行われるかは、割り当て方法によって異なります。ByteBuffervoid*

  • でダイレクト バイト バッファを割り当てた場合ByteBuffer.allocateDirect()、Dalvik がストレージを所有します。ByteBufferが到達不能になり、ガベージ コレクションが行われると解放されます。
  • ByteBuffer自分でストレージを割り当て、それをJNI呼び出しで関連付けた場合、ストレージNewDirectByteBufferは解放するまで有効です。

このallocateDirect()場合、マネージ コードがByteBuffer. これを行う 1 つの方法はByteBuffer、ネイティブ コードで へのグローバル参照を保持し、グローバル参照を削除すると同時にバッファ ポインタを無効にすることです。コードの構造によっては、必要ない場合があります。

JNI のヒントページも参照してください。

于 2013-06-26T22:52:53.977 に答える