jni local refernces
7341 ワード
So far, we have used data types such as
jobject
, jclass
, and jstring
to denote references to Java objects. However, the JNI creates references for all object arguments passed to native methods, as well as all objects returned from JNI functions. References serve to keep the Java objects from being garbage collected. By default, the JNI creates local references because local references ensure that the Java Virtual Machine can eventually free the Java objects. Local references become invalid when program execution returns from the native method in which the local reference is created. Therefore, a native method must not store away a local reference and expect to reuse it in subsequent invocations.
For example, the following program, which is a variation of the native method in
FieldAccess.c
, mistakenly caches the Java class for the member variable ID so that it does not have to repeatedly search for the member variable ID based on the member variable name and signature at each invocation: /* This code is illegal
*/
static jclass cls = 0;
static jfieldID fld;
JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
...
if (cls == 0) {
cls = (*env)->GetObjectClass(env, obj);
if (cls == 0) {
... /* error */
}
fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
}
/* access the member variable using cls and fid */
...
}
This program is illegal because the local reference returned from
GetObjectClass
is valid only until the native method returns. When the Java application calls the native method Java_FieldAccess_accessFields
a second time, the native method tries to use an invalid local reference. This leads to either the wrong results or to a VM crash. You can overcome this problem by creating a global reference . A global reference remains valid until it is explicitly freed. The following code rewrites the previous program and correctly uses a global reference to cache the class for the member variable ID:
/* This code is correct.
*/
static jclass cls = 0;
static jfieldID fld;
JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
...
if (cls == 0) {
jclass cls1 = (*env)->GetObjectClass(env, obj);
if (cls1 == 0) {
... /* error */
}
cls = (*env)->NewGlobalRef(env, cls1);
if (cls == 0) {
... /* error */
}
fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
}
/* access the member variable using cls and fid */
...
}
A global reference keeps the Java Virtual Machine from unloading the Java class, and therefore also ensures that the member variable ID remains valid, as discussed in Accessing Java Member Variables . However, the native code must call
DeleteGlobalRef
when it no longer needs access to the global reference. Otherwise, the Java Virtual Machine will never unload the corresponding Java object, the Java class referenced by cls
above. In most cases, the native programmer should rely on the Java Virtual Machine to free all local references after the native method returns. In certain situations, however, the native code may need to call the
DeleteLocalRef
function to explicitly delete a local reference. These situations are: lref
when it is running inside lengthyComputation
: ...
lref = ... /* a large Java object */
... /* last use of lref */
(*env)->DeleteLocalRef(env, lref);
lengthyComputation(); /* may take some time */
return; /* all local refs will now be freed */
}
arr
consisting of Java strings. After each iteration, the program can free the local reference to the string element: ...
for(i = 0; i < len; i++) {
jstring jstr = (*env)->GetObjectArrayElement(env, arr, i);
... /* processes jstr */
(*env)->DeleteLocalRef(env, jstr); /* no longer needs jstr */
}
...
********************************************************
表示されない削除では、ReferenceTable overflow(max=512)が表示される場合があります.
私はこのような問題が発生したことがあります.LOGは以下の通りです.
********************************************************
解決方法:(引用:http://hi.baidu.com/lihn1987/blog/item/73fb281ac1a61cdaac6e752c.html)
ReferenceTable overflow(max=512)の解決について
最近1つの問題に出会って、晩に長い間解決方法を見つけていないで、最後に自分で考えて解決して、特にみんなと分かち合って、誰かが同じ問題に遭遇しないようにします.
私のこの間違いはこのように発生したのです.私のプログラムはjavaのjni機能を多く使用しており、JavaとCが頻繁に呼び出されることがあります.これにより、プログラムがしばらく実行されると、問題で述べた内容ReferenceTable overflow(max=512)が表示されます.
Javaのゴミ処理にはリファレンスカウントというものがありますが、私がここで見たエラーはこの問題を言っているようで、リファレンスカウントテーブルがあふれていますか?
そこで私は自分のコードを探して、ひっきりなしに遮蔽して、間違いが意外にもcの中でjavaを呼び出す時のこのような一言の中でjc=(*ev)->GetObjectClass(m_obj);
ここでjcはjavaclassの変数ですが、この言葉が漏れてjavaの参照カウントが増え続けているのではないでしょうか.あるいはこの言葉が他の何かに影響を及ぼしたのだろうか.
そこでgoogleを始めて、结果は人がGetObjectClassを呼び出す时すべてどんな釈放の东を呼び出すことを発见して、まさかあのjcは釈放する必要があります???
自分でn久を探してjcを使わない時m_を呼び出すことを発見しましたenv->DeleteLocalRef(jc);問題は解決した