2011-07-18 251 views
4

是否可以在JNI中引用整個字節數組而不調用任何副本?如何在JNI中讀取bytearray?

在原生的C代碼,我有一個字節組從Java傳球,我只是想將一些數據比較,此ByteArray所以我不想做任何內存拷貝。可能嗎 ?

我知道我可以通過使用GetPrimitiveArrayCritical類似的東西

JNIEXPORT jbyteArray JNICALL Java_nfore_android_bt_pro_nfhfp_dsp 
(JNIEnv *env, jobject jobj, jbyteArray jbIn, jbyteArray jbBase){ 

    jbyte *bufferIn; 
    jbyte *bufferBase; 
    bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL); 

    LOGD("Begin of dsp()"); 
    LOGD("In dsp() Before Comparing..."); 

     // Compare bufferIn with bufferBase here... 

    LOGD("In dsp() After Comparing..."); 
    LOGD("End of dsp()"); 

    (*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0); 

    return jbIn; 
} 

正如你可以看到,因爲我可能會改變在jbIn數據獲得原生的ByteArray的指針,我應該用GetPrimitiveArrayCritical獲得它的指針並在稍後釋放它。

但是,如果我只是想讀的ByteArray jbBase,我怎麼可能讓jbBase的指針,但沒有使用GetPrimitiveArrayCritical?

任何建議,將不勝感激。非常感謝。

回答

9

我用下面的讀取字節數組...

jbyte *b = (jbyte *)env->GetByteArrayElements(jbBase, NULL); 
// read bytes in *b here 
... 
// release it 
env->ReleaseByteArrayElements(jbBase, b, 0); 

你仍然需要爲停止垃圾收集器,而你還在使用它擺脫它潛在地將其釋放。

+0

謝謝你的回覆,吉姆。通過規格指南,GetByteArrayElements仍然可能會複製,對吧?此外,GetByteArrayElements將獨佔模式設置爲這個bytearray?如果我還需要同時讀取其他線程中的這個bytearray,它會發生衝突嗎?謝謝。 –

+2

它不設置獨佔模式,但如果您只讀數組,那麼併發訪問應該是OK。如果它可以同時寫入,那麼您將需要使用互斥鎖或同步。我不知道它是否做了副本,據我可以告訴它只是返回一個指向數組的指針,我使用它作爲高性能編解碼器,我從來沒有注意到它複製數組,雖然它很難說如果它做了一個副本。 –

+0

好的,我明白了。謝謝你的幫助吉姆。 –

6

GetByteArrayElements方法不能保證你的程序中使用的參考或複製。 JNI返回isCopy標誌,表示它複製對象或固定它(引腳表示引用)。如果你不想複製它從來沒有,你沒有使用GetArrayElements方法,因爲它總是返回副本(JVM決定複製與否,並可能複製首選,因爲複製緩解垃圾收集器的負擔)。我試了一下,發現陣容大的時候我的內存增加了。你也可以看到,在下面的鏈接:

IBM copy and pin(看從樹視圖複製和銷主體)

由於文件說,GetPrimitiveArrayCritical返回Java數組的直接堆地址,禁止垃圾收集,直到相應的ReleasePrimitiveArrayCritical被調用。所以你必須使用GetPrimitiveArrayCritical,如果你不想複製(當你有一個大數組時,你需要這個)。如果我們看一下你的代碼,你可以通過一個如下得到陣列一個(我假設你送int數組作爲jobject到JNI功能):

length = (*env)->GetArrayLength(jbIn); 
bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL); 
for(int i=0; i<length; i++) 
    printf("Value of jbIn[%d]: %d", i, bufferIn[i]); 
(*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0); 

重要提示:GetPrimitiveArrayCritical後,您不能GetArrayLength因爲JNI沒有按」 t允許程序在獲取關鍵和釋放方法之間爲同一對象調用任何JNI函數。