6

コードを実行すると、「512 エントリの JNI ローカル ref テーブルへの追加に失敗しました」というエラーが表示されます。

これは私のコードです:

jstring pJNIData = pJNIEnv->NewStringUTF ( variables[0].GetStringValue() );

pJNIEnv->CallStaticVoidMethod ( pJNIActivityClass, pJNIMethodIDStartTime, pJNIData ) ;

pJNIEnv->DeleteLocalRef(pJNIData);

いくつかの提案を読みましたが、どれも機能しません! にもかかわらず、DeleteLocalRef動作しません。関数は、文字通りすべての関数を呼び出すプロファイラーで使用されます...

4

2 に答える 2

2

これは、JNIメソッドがJavaコードと呼ばれるときに見たものです(私の場合、メソッドは静的ではありませんでした)。私が理解しているように、未使用のローカル参照は、JavaメソッドがJNIから呼び出されたときに(つまり、最上位のJNI関数が戻るまで)自動的に削除されません。

IIRCは、ログにメモリオブジェクトに関する情報がすでに存在するか、ログを追加することができます。その情報から、以前は触れなかったゴミを特定しました。それらは2つの配列と1つのクラスであり、後続の呼び出しで作成されましたが、ガベージコレクションは行われませんでした。

// in a function that calls a Java method from JNI
jbyteArray srcArray = env->NewByteArray(len);
jclass cls = env->FindClass("com/something/MyClass");
jmethodID mid = env->GetMethodID(cls, "mymethod", "([BI)[B");
jbyteArray resArray = (jbyteArray)env->CallObjectMethod(obj, mid, srcArray, XXXX);

...
env->DeleteLocalRef(cls);
env->DeleteLocalRef(resArray);
env->DeleteLocalRef(srcArray);
// no need to do anything with mid

これらの3つのローカル参照は異なる方法で取得されましたが、すべてがぶらぶらしていたことに注意してください。

便利なリンク: http: //www.netmite.com/android/mydroid/dalvik/docs/jni-tips.html#local_vs_global_references (または、DalvikVMドキュメントdalvik/ docs / jni-tips.htmlを見つけて、「ローカル」セクションを見つけます。 vs.グローバルリファレンス")

JNIが返すすべてのオブジェクトは、「ローカル参照」です。これは、現在のスレッドの現在のネイティブメソッドの期間中有効であることを意味します。ネイティブメソッドが戻った後もオブジェクト自体が存続している場合でも、参照は無効です。これは、jclassやjarrayを含むjobjectのすべてのサブクラスに適用されます。[...]注:メソッドIDとフィールドIDは単なる32ビット識別子であり、オブジェクト参照ではないため、NewGlobalRefに渡さないでください。GetStringUTFCharsやGetByteArrayElementsなどの関数によって返される生データポインタもオブジェクトではありません。

于 2012-12-24T12:01:04.530 に答える
0

他の誰かがこの問題に遭遇した場合に備えて、チップを入れると思いました. これは私を何時間も混乱させた奇妙な事件です!

わかりましたので、NDK アプリがあり、呼び出される Java コードは、実行時に読み込まれる apk 内にあります。ランタイムの読み込みがこれに何らかの影響を与えるかどうかはわかりませんが、言及する必要があると思いました.

C++ メソッドでは、find class と getmethodid を使用してコンストラクターを HashMap に取得し、それを呼び出して新しい HashMap インスタンスを取得します。次に、jni 呼び出しを使用して C++ 側から HashMap を設定します。ここまでは順調ですね。次に、HashMap を Java コードに渡すと、すべてが期待どおりに機能しています。Java コードが返されたら、HashMap で DeleteLocalRef を呼び出します。エラーはスローされませんが、参照は削除されません。

これは、最終的に 512 を超えるローカル参照 (この関数への複数の呼び出しから) を実行したときにのみ発生し、エラー ダンプは、localref ストア内の最後の 10 項目がほぼすべて HashMap であることを示しました。マルチスレッドのndkアプリを作成しているため、メソッドの最後でGCがこれらの参照を収集しないことを理解しています。ただし、DeleteLocalRef は機能しているはずです。

修正: 最終的に、私が書いた Java メソッドへの jni 呼び出しから HashMap を作成することは問題なく、参照は解放可能であることがわかりました。文字通り新しいHashMapを返すだけのJava関数を持つのはクレイジーに思えますが、それはうまくいったので、今のところ私はそれと一緒に暮らしています:)

于 2014-05-26T22:29:41.520 に答える