2

My application makes multiple calls from native threads to java, i am seeing the memory usage of the application slowly creeping up. It looks like the calls to attach and detach cause JAVA to leak a thread. I can see this by running DDMS memory analyser.

I have written a really simple test app that demonstrates my issue, start test is called from JAVA and kicks off the thread. It doesn't do anything other then attach and then detach the worker thread.

void detachFromThread(JavaVM *vm)
{

  if(vm != NULL)
  {
      vm->DetachCurrentThread();
  }
  else
  {

      __android_log_write(ANDROID_ LOG_ERROR, "JNI", "JNIUtils detachFromThread invalid VM passed in");
  }
}

JNIEnv* attachToThread(bool &attached, JavaVM *vm)
{
    JNIEnv *theJNIEnv(NULL);

    attached = false;

    if(vm != NULL)
    {
        jint result = vm->GetEnv((void **)& theJNIEnv, JNI_VERSION_1_6);

        if (result != JNI_OK)
        {
            vm->AttachCurrentThread(&theJNIEnv, NULL);

            if(theJNIEnv->ExceptionCheck())
            {
                theJNIEnv->ExceptionDescribe();
                theJNIEnv->ExceptionClear();

        __android_log_write(ANDROID_ LOG_ERROR, "JNI", "JNIUtils attachToThread failed to attach");

                theJNIEnv = NULL;
            }
            else
            {
                attached = true;

            }
        }
    }
    else
    {
        __android_log_write(ANDROID_ LOG_ERROR, "JNI", "JNIUtils attachToThread invalid VM passed in");
    }

return theJNIEnv;
}

bool checkForJNIException(JNIEnv * theJNIEnv)
{

    bool ret = false;

    if(theJNIEnv->ExceptionCheck())
    {

        ret = true;

        __android_log_write(ANDROID_ LOG_ERROR, "JNI", "JNI Error occurred");

        theJNIEnv->ExceptionDescribe();

        theJNIEnv->ExceptionClear();
    }

return ret;

}

void workerFunc(int noLoops)
{
    for(int i = 0; i < noLoops; i++)
    {

        bool attached(false);

        JNIEnv *testEnv = attachToThread(attached, g_vm);

        if(attached)
            detachFromThread(g_vm);

        boost::posix_time::milliseconds sleepTime(1+ (rand()%(100)));

        boost::this_thread::sleep(sleepTime);

    }
}

void Java_com_example_testapp_ jnithreadtest_startTest(JNIEnv* env, jobject javaThis, int noLoops, int noThreads)
{
    for(int i = 0; i < noThreads; i++)
        boost::thread workerThread(workerFunc, noLoops);

}

Am i missing something, do I need to free something else up.

user1145533
  • 687
  • 3
  • 12
  • 24
  • 1
    It shouldn't be leaking. When the thread detaches from the VM, the VM removes the `Thread` from the "main" `ThreadGroup` and from its internal data structures. The only time you should see a leak is if the TraceView method profiling is enabled (http://stackoverflow.com/questions/21897288/21916242#21916242). Using an analysis tool like HAT or MAT you should be able to see any leaked `Thread` objects and determine what root-set object is keeping them alive. – fadden Mar 11 '14 at 20:14
  • #fadden i have trird using MAT and it is definatly leaking. It is definatly the java thread that is used to attach to the jvm that leaks as you can see yhe thread names in MAT. Is there a way to force a jvm to tidy its threads? – user1145533 Mar 12 '14 at 12:14
  • 1
    You can use the "force GC" button in DDMS to cause garbage collection to happen. It's a good idea to use that before grabbing the heap snapshot. If the Thread objects are still around, it's because something still has a reference to them. The analysis tools should be able to tell you what the root object is. – fadden Mar 12 '14 at 14:33
  • were you able to resolve this? I am experimenting the same exact issue. See my question: http://stackoverflow.com/questions/40028626/jni-error-app-bug-weak-global-reference-table-overflow-why – gmmo Oct 18 '16 at 19:28

0 Answers0