为什么需要释放在JNI本机函数中创建的全局引用?

我有一个Java类,具有使用C

++实现的本机函数,称为nz.ac.unitec.BigInteger。的本机实现nz.ac.unitec.BigInteger很简单,只是包裹java.math.BigInteger,并调用它的构造函数和addsubtractmultiply…功能。一个字段mNativeContextnz.ac.unitec.BigInteger用于存储的全局引用一个java.math.BigInteger对象。该对象具有终结器,该终结器应该在垃圾回收对象时破坏全局引用,因此我不会泄漏全局引用。

当我运行一个简单的测试循环以创建多个nz.ac.unitec.BigInteger对象而不显式释放所创建的对象时,在日志(LOG1)之后报告了JNI错误。但是,如果我在离开测试功能之前显式释放创建的对象,则压力测试可以成功执行。

当我有终结器要在垃圾回收对象中删除它们时,为什么JVM的全局引用用完了?

LOG1:

F/art     (10730): art/runtime/indirect_reference_table.cc:113] JNI ERROR (app bug): global reference table overflow (max=51200)

F/art (10730): art/runtime/indirect_reference_table.cc:113] global reference table dump:

F/art (10730): art/runtime/indirect_reference_table.cc:113] Last 10 entries (of 51200):

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51199: 0x12e88790 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51198: 0x12e85490 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51197: 0x12e81790 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51196: 0x12e7e760 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51195: 0x12e7ab20 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51194: 0x12e77790 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51193: 0x12e73a90 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51192: 0x12e71af0 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51191: 0x12e6dd60 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] 51190: 0x12e6b9a0 java.math.BigInteger

F/art (10730): art/runtime/indirect_reference_table.cc:113] Summary:

F/art (10730): art/runtime/indirect_reference_table.cc:113] 1456 of java.math.BigInteger (1456 unique instances)

F/art (10730): art/runtime/indirect_reference_table.cc:113] 2 of android.opengl.EGLDisplay (2 unique instances)

F/art (10730): art/runtime/indirect_reference_table.cc:113] 1889 of java.math.BigInteger (1889 unique instances)

F/art (10730): art/runtime/indirect_reference_table.cc:113] 1 of java.lang.String

F/art (10730): art/runtime/indirect_reference_table.cc:113] 27 of java.math.BigInteger (27 unique instances)

F/art (10730): art/runtime/indirect_reference_table.cc:113] 1 of java.lang.String

F/art (10730): art/runtime/indirect_reference_table.cc:113] 3771 of java.math.BigInteger (3771 unique instances)

F/art (10730): art/runtime/indirect_reference_table.cc:113] 1 of dalvik.system.PathClassLoader

F/art (10730): art/runtime/runtime.cc:284] Runtime aborting...

F/art (10730): art/runtime/runtime.cc:284] Aborting thread:

计算器.java

package nz.ac.unitec.calculator;

public class MainActivity extends AppCompatActivity

{

protected void onCreate(Bundle savedInstanceState)

{

Random ra = new Random();

for(int i=0; i<6000000; ++i) {

testCreateFinalize(ra);

int m = ra.nextInt();

int n = 8;

int re = m + n;

Log.i("MainActivity", "re=" + re);

//BigInteger result = l.subtract(r);

}

private void testCreateFinalize(Random ra)

{

BigInteger l = new BigInteger("100", 10);

BigInteger r = new BigInteger("200", 10);

//l.release(); when adding this two code lines, the test is ok

//r.release();;

}

}

BigInteger.java

package nz.ac.unitec.mathutils;

public class BigInteger

{

static {

System.loadLibrary("BigInteger_jni");

native_init();

}

private long mNativeContext;

private BigInteger()

{

mNativeContext = 0;

native_setup();

}

public BigInteger(String val, int radix)

{

mNativeContext = 0;

native_setup_bystring(val, radix);

}

public void release() {

native_finalize();

}

protected void finalize() {

native_finalize();

}

private static native final void native_init();

private native final void native_setup();

private native final void native_setup_bystring(String val, int radix);

private native final void native_finalize();

public native String toString(int radix);

public native BigInteger add(BigInteger rval);

public native BigInteger multiply(BigInteger rval);

public native BigInteger subtract(BigInteger rval);

}

本机代码

static jobject getNativeBigInteger_l(JNIEnv* env, jobject thiz)

{

return reinterpret_cast<jobject> (env->GetLongField(thiz, fields.context)); //reinterpret_cast<jobject>

}

static void setNativeBigInteger_l(JNIEnv* env, jobject thiz, jobject bi)

{

env->SetLongField(thiz, fields.context, reinterpret_cast<jlong>(bi)); //reinterpret_cast<jlong>

}

JNIEXPORT void JNICALL Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring

(JNIEnv *env, jobject thiz, jstring val, jint radix)

{

jclass cls = env->FindClass(gBuiltinClassBigInteger);

ALOGV("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->FindClass(%s) return (%0x)",

gBuiltinClassBigInteger, cls);

if (cls == NULL) {

ALOGE("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->FindClass(%s) return NULL", gBuiltinClassBigInteger);

return;

}

jmethodID constructor = env->GetMethodID(cls, "<init>", "(Ljava/lang/String;I)V");

if (constructor == NULL) {

env->DeleteLocalRef(cls);

ALOGE("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->GetMethodID(%s) return NULL", "<init>");

return;

}

jobject jobj = env->NewObject(cls, constructor, val, radix);

ALOGV("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->NewObject return (%0x)",

jobj);

if (NULL == jobj) {

env->DeleteLocalRef(cls);

ALOGE("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->NewObject return NULL");

return;

}

jobject gjobj = env->NewGlobalRef(jobj);

ALOGV("-Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring env->NewGlobalRef return (%0x)", gjobj);

setNativeBigInteger_l(env, thiz, gjobj);

env->DeleteLocalRef(jobj);

//env->DeleteLocalRef(cls);

}

JNIEXPORT void JNICALL

Java_nz_ac_unitec_mathutils_BigInteger_native_1finalize

(JNIEnv *env, jobject thiz)

{

ALOGV("+native_finalize");

jobject obj = getNativeBigInteger_l(env, thiz);

ALOGV("-Java_nz_ac_unitec_mathutils_BigInteger_native_1finalize getNativeBigInteger_l return (%0x)",

obj);

if (obj == NULL) {

ALOGE("-native_finalize getNativeBigInteger_l NULL");

return;

}

env->DeleteGlobalRef(obj);

setNativeBigInteger_l(env, thiz, NULL);

ALOGV("-native_finalize");

}

static JNINativeMethod gMethods[] = {

{"native_init", "()V",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_native_1init},

{"native_setup", "()V",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_native_1setup},

{"native_setup_bystring", "(Ljava/lang/String;I)V",

(void*)Java_nz_ac_unitec_mathutils_BigInteger_native_1setup_1bystring},

{"native_finalize", "()V",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_native_1finalize},

{"add", "(Lnz/ac/unitec/mathutils/BigInteger;)Lnz/ac/unitec/mathutils/BigInteger;",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_add},

{"multiply","(Lnz/ac/unitec/mathutils/BigInteger;)Lnz/ac/unitec/mathutils/BigInteger;",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_multiply},

{"subtract","(Lnz/ac/unitec/mathutils/BigInteger;)Lnz/ac/unitec/mathutils/BigInteger;",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_subtract},

{"toString","(I)Ljava/lang/String;",

(void *)Java_nz_ac_unitec_mathutils_BigInteger_toString}

};

int register_Java_nz_ac_unitec_mathutils_BigInteger(JNIEnv *env)

{

return jniRegisterNativeMethods(env, gClassBigInteger, gMethods, NELEM(gMethods));

}

回答:

您的代码失败,因为您对尚未释放回内存池中的对象的全局引用过多。全局引用表的最大大小可帮助您捕获内存泄漏并防止程序内存不足。您粘贴的日志消息告诉您这些对象是什么:java.math.BigInteger

如果查看您的实现,native_setup_bystring可以看到您正在创建对新BigInteger对象的全局引用:

jobject gjobj = env->NewGlobalRef(jobs);

全局引用不会自动垃圾收集[1]

[2],因此您需要显式删除它们,这是在测试中找到的。

方法的问题在于,您正在使用对堆(您的long mNativeContext字段)中的直接内存引用来存储对内部对象的引用

。这种方法不是一个好方法,因为您要阻止JVM管理BigIntegers的垃圾回收。更好的方法是完全避免使用全局引用,而存储对象引用而不是long。如果执行此操作,则JVM将能够自动收集要分配的所有对象。

以上是 为什么需要释放在JNI本机函数中创建的全局引用? 的全部内容, 来源链接: utcz.com/qa/413904.html

回到顶部