Joan P.S
Joan P.S

Reputation: 1573

JNI "local reference table overflow" when using NewGlobalRef

I'm developing an app that uses JNI but I'm getting a "local reference table overflow" error when using global references:

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

The code goes as follows:

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();
}

When I create a big loop that creates and destroy 1000 Foo instances and run doSomething, I get the error "local reference table overflow" but if I don't use NewGlobalRef as follows, I do not get any crash:

class Foo {
public:
    Foo(){}
    void doSomething(){
        JNIEnv* env = getEnv();
        jobject javaObject = env->CallStaticObjectMethod(...);
        env->DeleteLocalRef(javaObject);
    }
    ~Foo() {
    }
};

Anybody knows what I'm missing here?

Upvotes: 2

Views: 1552

Answers (1)

Michael
Michael

Reputation: 58467

CallStaticObjectMethod returns a local reference to whatever it is you're creating (which implies that the local reference will be added to the current thread's local reference table).

Unless you return back to java or detach the native thread from the VM, that reference table isn't going to be cleared. And if you keep creating local references without clearing the local reference tables, you're eventually going to run out of free entries in the table.

Your fixed version takes care of this by deleting each local reference immediately after you're done using it.

The point of global references is that they won't be automatically deleted when you return back to java or detach the current thread, so you can use that same reference later on. But in your case you don't seem to need that, although your example looks a bit contrived (you create objects that you never use).

Upvotes: 2

Related Questions