我有一个Java类,具有使用C
++实现的本机函数,称为nz.ac.unitec.BigInteger
。的本机实现nz.ac.unitec.BigInteger
很简单,只是包裹java.math.BigInteger
,并调用它的构造函数和add
,subtract
,multiply
…功能。一个字段mNativeContext
中nz.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将能够自动收集要分配的所有对象。
我有一个Java类,其中包含用C语言实现的本机函数,称为。的本机实现很简单,只需包装并调用其构造函数和、、…函数。
函数注释似乎重复了Python中已经发现的行为。不仅如此,它们的含义没有以任何方式强制执行,因此它们可以用于PEP 3107中记录的以下任何一项: 提供打字信息 类型检查 让IDE显示函数期望和返回的类型 函数重载/泛型函数 外语桥梁 改编 谓词逻辑函数 数据库查询映射 RPC参数封送 其他信息 参数和返回值的文档 甚至是完全不同的东西。 在某种程度上,函数注释让我想起Python幽默系列中的一个
我读过几篇关于JNI本地和全球的参考文献。但是我找不到一个明确的答案,作为参数传递给JNI函数的Java对象是局部引用还是全局引用。我认为它应该是全球性的,但是有一个问题: 首先,我获取Java对象指针并保存它。然后,本机回调函数调用该对象的方法。回调函数是从单独的线程调用的。线程是使用AttachCurrentThread()创建的,因此JVM知道它。JNIEnv*变量也是有效的,对象没有被垃圾
问题内容: 如果函数需要修改在全局范围内声明的变量,则需要使用全局声明。但是,如果函数只需要读取全局变量,则可以不使用全局声明而这样做: 我的问题是关于Python的设计的:为什么Python被设计为允许在不使用全局声明的情况下读取全局变量?也就是说,为什么只强制分配具有全局性,为什么不强制全局读取呢?(这将使它变得均匀而优雅。) 注意:我可以看到在读取时没有歧义,但是在分配时并不清楚是否打算创建
问题内容: 我对此代码有疑问:https : //github.com/reactjs/redux/blob/master/examples/async/containers/App.js 特别: 我猜这是一个两部分的问题。 为什么我需要将句柄更改设置为类的实例,我不能只对handleChange使用静态函数并直接在类中调用它 ? 我不知道这是怎么回事: 谢谢 问题答案: 以相反的顺序回答… 返回
JNI参考文献中说 “本地引用在本机方法调用期间有效。它们在本机方法返回后自动释放。 资料来源:http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#global_local 我有点迷路了。根据上述内容,我必须显式调用NewGlobalRef并传递从调用NewObject返回的对象。我试过这个,似