当前位置: 首页 > 知识库问答 >
问题:

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

严劲
2023-03-14

我有一个Java类,其中包含用C语言实现的本机函数,称为nz.ac.unitec.BigIntegernz.ac.unitec.BigInteger的本机实现很简单,只需包装java.math.BigInteger并调用其构造函数和add减去…函数。nz.ac.unitec.BigInteger中的字段mNativeContext用于存储对java.math.BigInteger对象的全局引用。该对象有一个终结器,当对象被垃圾收集时,它应该会销毁全局引用,这样我就不会泄露全局引用。

当我运行一个简单的测试循环来创建许多< code > NZ . AC . unitec . big integer 对象,而没有显式释放创建的对象时,一个JNI错误被报告为如下日志(LOG1)。但是,如果我在离开测试函数之前显式释放创建的对象,压力测试就可以成功执行

当对象被垃圾收集时,当我有一个终结器来删除它们时,为什么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));
}

共有1个答案

钱和安
2023-03-14
匿名用户

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

如果您查看< code > native _ setup _ by string 的实现,您会发现您正在创建一个对新的< code>BigInteger对象的全局引用:

jobject gjobj = env->NewGlobalRef(jobs);

全局引用不会自动进行垃圾收集[1][2],所以您需要显式删除它们,这是您在测试中发现的。

这种方法的问题在于,您使用直接内存引用将对内部对象的引用存储到堆中(您的< code>long mNativeContext字段)。这种方法并不好,因为它阻止了JVM管理大整数的垃圾收集。更好的方法是完全避免使用全局引用,而是存储对象引用而不是< code>long。如果你这样做,那么JVM将能够自动收集你正在分配的所有对象。

 类似资料:
  • 问题内容: 我有一个Java类,具有使用C ++实现的本机函数,称为。的本机实现很简单,只是包裹,并调用它的构造函数和,,…功能。一个字段中用于存储的全局引用一个对象。该对象具有终结器,该终结器应该在垃圾回收对象时破坏全局引用,因此我不会泄漏全局引用。 当我运行一个简单的测试循环以创建多个对象而不显式释放所创建的对象时,在日志(LOG1)之后报告了JNI错误。但是,如果我在离开测试功能之前显式释放

  • 函数注释似乎重复了Python中已经发现的行为。不仅如此,它们的含义没有以任何方式强制执行,因此它们可以用于PEP 3107中记录的以下任何一项: 提供打字信息 类型检查 让IDE显示函数期望和返回的类型 函数重载/泛型函数 外语桥梁 改编 谓词逻辑函数 数据库查询映射 RPC参数封送 其他信息 参数和返回值的文档 甚至是完全不同的东西。 在某种程度上,函数注释让我想起Python幽默系列中的一个

  • 我读过几篇关于JNI本地和全球的参考文献。但是我找不到一个明确的答案,作为参数传递给JNI函数的Java对象是局部引用还是全局引用。我认为它应该是全球性的,但是有一个问题: 首先,我获取Java对象指针并保存它。然后,本机回调函数调用该对象的方法。回调函数是从单独的线程调用的。线程是使用AttachCurrentThread()创建的,因此JVM知道它。JNIEnv*变量也是有效的,对象没有被垃圾

  • 问题内容: 我知道弱引用是垃圾收集器的摆布,我们不能保证弱引用会存在。我认为没有必要提供较弱的参考,但可以确定应该有一个理由。 为什么我们需要Java中的弱引用? Java中弱引用的实际(某些)用法是什么?如果您可以分享您在项目中的使用方式,那就太好了! 问题答案: 使用弱哈希图实际上通常是一个坏主意。首先,很容易出错,但更糟糕的是,它通常用于实现某种缓存。 这意味着以下内容:您的程序在一段时间内

  • 我正在尝试按照本教程实现nodejs mysql数据库。我知道 查询()是Pool.GetConnection()+Connection.Query()+Connection.Release()的快捷方式。 在本文中,数据库配置为: 这是可以用作: 但是,我真的不明白 如果使用pool会自动释放连接,为什么我们需要这样做呢?

  • 问题内容: 如果函数需要修改在全局范围内声明的变量,则需要使用全局声明。但是,如果函数只需要读取全局变量,则可以不使用全局声明而这样做: 我的问题是关于Python的设计的:为什么Python被设计为允许在不使用全局声明的情况下读取全局变量?也就是说,为什么只强制分配具有全局性,为什么不强制全局读取呢?(这将使它变得均匀而优雅。) 注意:我可以看到在读取时没有歧义,但是在分配时并不清楚是否打算创建