2011-02-08 27 views
1

可以說,我有如下原型的函數:JNI,釋放原始的數組和內存不足異常

JNIEXPORT void JNICALL Java_example_SCLASS_cfunc 
(JNIEnv *env, jclass caller, jdoubleArray s, jdoubleArray u, jdoubleArray vt) 

我想要做這樣的事情:

{ 
    jdouble* S_native = (*env)->GetDoubleArrayElements(env, s, JNI_FALSE); 
    jdouble* U_native = (*env)->GetDoubleArrayElements(env, u, JNI_FALSE); 
    jdouble* VT_native = (*env)->GetDoubleArrayElements(env, vt, JNI_FALSE); 

    if(!S_native || !U_native || !VT_native){ 
    (*env)->ReleaseDoubleArrayElements(env, s, S_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, u, U_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0); 
    return; 
    } 

    /*Now Use the arrays in some way...*/ 

    (*env)->ReleaseDoubleArrayElements(env, s, S_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, u, U_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0); 
    return; 
} 

但我m不確定是否可以這樣做,因爲我在jni文檔中讀到 應該在生成java異常時返回, 即(* env) - > GetDoubleArray ...失敗。

所以我不確定如果在前一次失敗後再次調用GetDoubleArray會發生什麼。

所以在面對不確定性的我煩人已經格式化,像這樣我的代碼:

{ 
    jdouble* S_native; 
    jdouble* U_native; 
    jdouble* VT_native; 

    S_native = (*env)->GetDoubleArrayElements(env, s, JNI_FALSE); 
    if(!S_native){ 
    return; 
    } 

    U_native = (*env)->GetDoubleArrayElements(env, u, JNI_FALSE); 
    if(!U_native){ 
    (*env)->ReleaseDoubleArrayElements(env, s, S_native, 0); 
    return; 
    } 

    VT_native = (*env)->GetDoubleArrayElements(env, vt, JNI_FALSE); 
    if(!VT_native){ 
    (*env)->ReleaseDoubleArrayElements(env, s, S_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, u, U_native, 0); 
    return; 
    } 

    /*Now Use the arrays in some way...*/ 

    (*env)->ReleaseDoubleArrayElements(env, s, S_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, u, U_native, 0); 
    (*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0); 
    return; 
} 

這是必要的或我能做到這一點的第一種方式?

回答

3

首先仔細閱讀Get<TYPE>ArrayElements函數的文檔。它的第三個參數是一個指針,通過它可以從函數返回的附加信息(是本地數組的副本)。您的解決方案只能工作,因爲JNI_FALSE等於NULL。

所以,如果你真的需要,你應該已經寫:

jboolean isCopy; 
jdouble* nativeArr = (*env)->GetDoubleArrayElements(env, arr, &isCopy); 

然後,你知道,如果你複製操作數組或固定的。 MOST雖然你不需要這些信息。你只是在一個簡單的方法兩種功能:

jdouble* nativeArr = (*env)->GetDoubleArrayElements(env, arr, NULL); 
// check nativeArr != NULL 
// operate on array 
(*env)->ReleaseDoubleArrayElements(env, arr, nariveArr, 0); 

考慮釋放資源和錯誤檢查:如果我們收到NULL從Get<>ArrayElements這意味着我們內存不足和性交。應用程序無法運行此錯誤後,所以我不會關心已分配的資源。留給系統清理。

但對於這一解決方案的工作,因爲它應該你需要從你的代碼提高OutOfMemoryError

我使用宏在我的項目進行清理代碼:

#define D_ARR_GET(narray, array) if((narray = (*env)->GetDoubleArrayElements(env, (array), NULL)) == NULL) { sendOutOfMemory(env); return; } 
#define D_ARR_FREE(narray, array) ((*env)->ReleaseDoubleArrayElements(env, (array), (narray), 0)) 

void sendOutOfMemory(JNIEnv* env) { 
    jclass oomCls = (*env)->FindClass(env, "java_lang_OutOfMemoryError"); 
    jmethodID errInit = (*env)->GetMethodID(env, oomCls, "<init>", "void(V)"); 
    jobject exc = (*env)->NewObject(env, oomCls, errInit); 

    (*env)->ExceptionClear(env); 
    (*env)->Throw(env, (jthrowable) exc); 
} 

void someJNIfunc(JNIEnv* env, jobject arr) { 
    jdouble* nativeArr; D_ARR_GET(nativeArr, arr); 
    // use nativeArr 
    D_ARR_FREE(nativeArr, arr); 
} 

記住比env->Throw並不意味着返回回Java,所以你如果需要的話需要return自己,通過本機幀存儲棧傳播(也許使用C++和異常來使它在更復雜的解決方案中不那麼繁瑣)。