Search code examples
javacjava-native-interface

releasing persistent arrays in JNI and C


I'm writing a wrapper to allow Java to access a library written in C.

There needs to be a persistent array between JNI calls. I'm retaining array address between calls. This method works very well. My main concern is when the array gets copied to jni from java that the memory gets freed by JVM but at the same time a copy stays on heap that I can reference and then free later when I'm done.

Here are the two functions, is the methodology correct or is there a more efficient way to do accomplish this?

Array Import to C:

JNIEXPORT jlong JNICALL
Java_Matcher_FlannLoadData(JNIEnv *env, jobject obj, jfloatArray d, jint r, jint c)
{
        int rows = (int)r;
        int cols = (int)c;

        float *jdataset = (*env)->GetFloatArrayElements(env,d,0);

        float *cdataset = malloc(rows*cols*sizeof(float));

        memcpy(cdataset,jdataset,rows*cols*sizeof(float));

        (*env)->ReleaseFloatArrayElements(env,d,jdataset,0);

        return (long)cdataset;
}

Free memory:

JNIEXPORT void JNICALL
Java_Matcher_FlannFreeData(JNIEnv *env, jobject obj, jlong d)
{
        free((float*)d)
}

Solution

  • I assume that

    1. as you stated that you are making a copy of Java data, you don't need the jlong for anything on Java side and you only pass it back to FreeData
    2. you don't insist on C-style memory management, as you are using dereference operator->

    Then there is a better way to do this, yes. Not necessarily more "efficient" (depends on what you mean) but cleaner and more readable for sure.

    float *cdataset;
    
    JNIEXPORT void JNICALL
    Java_Matcher_FlannLoadData(JNIEnv *env, jobject obj, jfloatArray d, jint r, jint c)
    {
        ...
        cdataset = new float[rows*cols];
        ...
    }
    
    JNIEXPORT void JNICALL
    Java_Matcher_FlannFreeData(JNIEnv *env, jobject obj)
    {
        delete [] cdataset;
    }