In my scenario I have a C++ library that makes multiple callbacks to Java code throughout the whole lifecycle of Android application. In my JNI code I had been attaching and detaching native thread to Java thread on every callback, like:
AttachCurrentThread(...)
// Java method call
DetachCurrentThread(...)
With such approach after multiple callbacks I get the following crash:
JNI ERROR (app bug): weak global reference table overflow (max=51200)
Full stack trace:
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] JNI ERROR (app bug): weak global reference table overflow (max=51200)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] weak global reference table dump:
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] Last 10 entries (of 51200):
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51199: 0x12cd6ac0 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51198: 0x12cd6a60 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51197: 0x12cd6a00 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51196: 0x12cd69a0 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51195: 0x12cd6940 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51194: 0x12cd68e0 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51193: 0x12cd6880 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51192: 0x12cd6820 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51191: 0x12cd67c0 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 51190: 0x12cd6760 java.lang.Thread
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] Summary:
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of com.dummy.app.AsrEngineTest$4$1
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of com.dummy.app.AsrEngineTest$1
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4009 of java.lang.Class (4009 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of java.lang.ThreadGroup
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (16 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (100 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (128 elements) (3 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (256 elements) (3 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (360 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 8 of byte[] (576 elements) (8 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (624 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (648 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 8 of byte[] (684 elements) (8 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (1024 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (1600 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (1920 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (2200 elements) (3 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (3072 elements) (3 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 9 of byte[] (4096 elements) (9 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (5632 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (7680 elements)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 29 of byte[] (9216 elements) (29 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (9408 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 16 of byte[] (11264 elements) (16 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 27 of byte[] (11664 elements) (27 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 50 of byte[] (13312 elements) (50 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (14336 elements)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (14352 elements)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (15376 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (15488 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (15876 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 127 of byte[] (16384 elements) (127 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 3 of byte[] (20736 elements) (3 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (24576 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (25920 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (32768 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 4 of byte[] (33792 elements) (4 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (36608 elements)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 6 of byte[] (36864 elements) (6 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 1 of byte[] (37636 elements)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (43616 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 2 of byte[] (92416 elements) (2 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 8 of byte[] (155136 elements) (8 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115] 244 of java.lang.Thread (244 unique instances)
com.dummy.app A/art: art/runtime/indirect_reference_table.cc:115]
com.dummy.app A/art: art/runtime/barrier.cc:90] Check failed: count_ == 0 (count_=-1, 0=0) Attempted to destroy barrier with non zero count
com.dummy.app A/art: art/runtime/runtime.cc:366] Runtime aborting --- recursively, so no thread-specific detail!
com.dummy.app A/art: art/runtime/runtime.cc:366]
com.dummy.app A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 7705 (Thread-47393)
Since the callbacks are made from only limited number of threads, I learned that this approach is not advised due to performance reasons. So I used the pthread_create_key destruct callback to automatically detach terminating thread and now the error is not the case, but still I would like to know what I was doing wrong.
Additional info:
I tested it on Nexus 7 with Android 6.0.1 device. I'm able to reproduce it with a loop of attach/detach calls. With such loop on Android 5.1.1 it also crashes but with different error code. On Android 4.4.2 (with Dalvik instead of ART as runtime environment) I got different behavior, an OutOfMemoryError exception was thrown after almost 400k iterations (GC was unable to free any memory).
Update - repro code source
JAVA PART: It has to be executed from the context of native thread.
// g_jvm is set on JNI_OnLoad
JNIEnv *env = NULL;
int res = 0;
int i;
for (i = 0; i < 100000; i++)
{
res = (*g_jvm)->GetEnv(g_jvm, (void**)&env, JNI_VERSION_1_6);
if (res == JNI_OK)
{
__android_log_print(ANDROID_LOG_DEBUG, "Debug", "Thread already attached %d", i);
}
else if (res == JNI_EDETACHED)
{
res = (*g_jvm)->AttachCurrentThread(g_jvm, &env, NULL);
if (res == JNI_OK)
{
__android_log_print(ANDROID_LOG_DEBUG, "Debug", "Thread attached: %d", i);
}
else
{
__android_log_print(ANDROID_LOG_ERROR, "Debug", "Failed to AttachCurrentThread");
break;
}
}
else
{
__android_log_print(ANDROID_LOG_ERROR, "Debug", "Failed to GetEnv");
}
res = (*g_jvm)->DetachCurrentThread(g_jvm);
if (res < JNI_OK)
{
__android_log_print(ANDROID_LOG_ERROR, "Debug", "Failed to DetachCurrentThread");
}
else
{
__android_log_print(ANDROID_LOG_DEBUG, "Debug", "Thread detached: %d", i);
}
}
C++ PART:
// need some time to separate from my case
After sequence of "Thread attached/detached" logs I got JNI ERROR with overflow.