java - 使用NewGlobalRef时的JNI “local reference table overflow”

我正在开发使用JNI的应用程序,但使用全局引用时出现“本地引用表溢出”错误:

art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): local reference table overflow (max=512)
 art/runtime/indirect_reference_table.cc:115] local reference table dump:
 art/runtime/indirect_reference_table.cc:115]   Last 10 entries (of 508):
 art/runtime/indirect_reference_table.cc:115]       507: 0x13f08b80 com.company.util.jni.JniCompanyHelper$HTTPStream
 art/runtime/indirect_reference_table.cc:115]       506: 0x13ef5520 com.company.util.jni.JniCompanyHelper$HTTPStream
 art/runtime/indirect_reference_table.cc:115]       505: 0x13eb4a80 com.company.util.jni.JniCompanyHelper$HTTPStream

代码如下:
class Foo {
public:
    Foo(){}
    void doSomething(){
        JNIEnv* env = getEnv();
        javaObject = env->NewGlobalRef(env->CallStaticObjectMethod(...));
    }
    ~Foo() {
        JNIEnv* env = getEnv();
        env->DeleteGlobalRef(javaObject);
    }
private:
    jobject javaObject;
};

// ...
// Run the loop in a separate thread
for(int i =0; i< 1000; i++) {
    Foo foo;
    foo.doSomething();
}

当我创建一个大循环,该循环创建并销毁1000个 Foo实例并运行 doSomething时,出现错误“本地引用表溢出”,但是如果我不按以下方式使用 NewGlobalRef,则不会崩溃:
class Foo {
public:
    Foo(){}
    void doSomething(){
        JNIEnv* env = getEnv();
        jobject javaObject = env->CallStaticObjectMethod(...);
        env->DeleteLocalRef(javaObject);
    }
    ~Foo() {
    }
};

有人知道我在这里想念的吗?

最佳答案

CallStaticObjectMethod返回对您正在创建的内容的本地引用(这意味着该本地引用将被添加到当前线程的本地引用表中)。

除非您返回java或从VM分离本机线程,否则不会清除该引用表。而且,如果您继续创建本地引用而没有清除本地引用表,则最终将耗尽表中的可用条目。

固定版本会在使用完毕后立即删除每个本地引用来解决此问题。

全局引用的要点是,当您返回java或分离当前线程时,它们不会被自动删除,因此以后可以使用相同的引用。但是在您的情况下,您似乎并不需要它,尽管您的示例看起来有些虚构(您创建了从未使用过的对象)。