Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JNI NewByteArray memory leak

I have a Java method that process a bitmap and returns a String. When I call this method from JNI (VS 2010) it works, but if I call this method many times, the memory of the process grown up until crash. The instruction that use a lot of memory is:

jbyteArray jBuff = _env->NewByteArray(b->Length);

My code:

static jobject staticArray=0;

System::String^ MyClass::ExecuteJavaMethod(System::Drawing::Bitmap^ bmp)
{
    JNIEnv *_env;
    System::String^ out;
    unsigned const char * buff;

    int res = jvm->AttachCurrentThread((void **)&_env, NULL);

    if (jvm->GetEnv((void**) &_env, JNI_VERSION_1_6) != JNI_OK)
    {
        return "GetEnv ERROR";
    }

    //save the bitmap in the stream
    MemoryStream^ ms = gcnew MemoryStream();
    bmp->Save(ms, ImageFormat::Bmp);

    //get the bitmap buffer
    array<unsigned char>^b = ms->GetBuffer() ;

    //unmanaged conversion
    buff = GetUnmanaged(b,b->Length);


    //fill the buffer
    jbyteArray jBuff = _env->NewByteArray(b->Length);       
    _env->SetByteArrayRegion(jBuff, 0, b->Length, (jbyte*) buff);

    //call the java method
    jstring str = (jstring) _env->CallStaticObjectMethod (  Main,
                                javaMethod,
                                jBuff);



    // _env->ReleaseByteArrayElements(jBuff,(jbyte*)buff), 0); //NOT WORKING

    //staticArray= _env->NewGlobalRef(jBuff);  NOT
    //_env->DeleteLocalRef(jBuff);             WORKING  


    //return the string result of the java method
    return gcnew String(env->GetStringUTFChars(str, 0));

}
like image 523
Rick Avatar asked Dec 20 '11 10:12

Rick


2 Answers

the answer is: _env->DeleteLocalRef(jBuff);

like image 50
Rick Avatar answered Nov 19 '22 22:11

Rick


You didn't call DetachCurrentThread() for each AttachCurrentThread(), which is requested in Java Native Interface Specification. That makes the local references (jBuff and str) unable to be freed automatically. Also, the const char* fetched through GetStringUTFChars() needs to be released.

The correct way is change

return gcnew String(env->GetStringUTFChars(str, 0));

into

const char* cstr = env->GetStringUTFChars(str, 0);
System::String^ retstr = gcnew String(cstr);
env->ReleaseStringUTFChars(str, cstr);
jvm->DetachCurrentThread();
return retstr;
like image 45
timrau Avatar answered Nov 19 '22 20:11

timrau