2009-07-22 142 views
11

我有一些本機代碼返回一個jbyteArray(所以在Java端的byte []),我想返回null。然而,如果我只是返回0來代替jbyteArray,我會遇到問題。從本地方法返回null使用JNI

一些更多信息: 主要邏輯是在Java中,本地方法用於將一些數據編碼成字節流。不要問...它必須這樣做。最近,本地代碼不得不稍微修改一下,現在它的運行速度非常糟糕。經過一些實驗,包括在返回之前註釋掉本地方法中的所有代碼,結果返回0導致放緩。當返回一個實際的jbyteArray時,一切都很好。

我的代碼的方法簽名:

在C++方面:

extern "C" JNIEXPORT jbyteArray JNICALL Java_com_xxx_recode (JNIEnv* env, jclass java_this, jbyteArray origBytes, jobject message) 

在Java方面:

private static native byte[] recode(byte[] origBytes, Message message); 

本機代碼看起來是這樣的:

jbyteArray javaArray; 
if (error != ERROR) { 
    // convert to jbyteArray 
    javaArray = env->NewByteArray((jsize) message.size); 
    env->SetByteArrayRegion(java_array, 0, message.size, reinterpret_cast<jbyte*>(message.buffer())); 
    if (env->ExceptionOccurred()) { 
     env->ExceptionDescribe(); 
     error = ERROR; 
    } 
} 
if (error == ERROR) { 
    return 0; // Does NOT work - doesn't crash, just slows everything down horrible. 
} 
else { 
    return javaArray; // Works perfectly. 
} 

有沒有人知道這可能發生的任何原因?從本地方法代替jbyteArray返回NULL是否有效,或者是否有其他過程將null返回給Java。不幸的是,我沒有在Google上運氣。

謝謝!

編輯:增加了額外的信息。

+0

爲什麼你返回0,而非陣列?爲什麼你不能簡單地返回一個空數組?請提供一些關於這個本地庫應該做什麼的更多細節。 – amischiefr 2009-07-22 17:46:41

+0

你可以發佈一些代碼,至少是方法簽名等? – 2009-07-22 20:10:57

+0

那麼,我特別希望Java接收「空」,而不是一個空字節數組。我可以重寫Java代碼來處理這個問題,但如果可能的話,我真的不想。我添加了方法簽名。 – Dan 2009-07-23 08:14:06

回答

-1

我不喜歡解決方案返回NULL。 如果可能的話,你應該返回像

return new ArrayList(); 
return new byte[0]; 
return new EmptySomeObjectImpl(); 

一些空實現比你不必擔心NullPointerExceptions的

if (error == ERROR) { 
    return env->NewByteArray(0); 
} 

編輯就

嘗試,如果你不想實現EmptyObjects總是返回此。

if (error == ERROR) { 
    return javaSrray; // Please test it and than return javaSrray always without if else 
} 
else { 
    return javaSrray; // Works perfectly. 
} 
0

有沒有在你的代碼,擊中我的眼睛有些不對稱:根據對象的類型,你永遠不會決定返回,返回「無」時除外。顯然env對象決定如何分配一個javaSrray,所以爲什麼不要求它返回某種空數組呢?有可能您返回的0需要在jni和java之間進行封送時以特殊方式處理。

0

你試過返回NULL引用嗎?

這是未經測試(不手邊有一個JNI的開發環境,此刻),但你應該能夠創建一個新的全球基準爲NULL,並返回它是這樣的:

return (*env)->NewGlobalRef(env, NULL); 

編輯被說,你檢查是否發生異常,但不清除它。據我所知,這意味着它仍然被「拋出」在Java層中,所以你應該只能用它作爲錯誤指示器;那麼函數返回的內容並不重要。實際上,根據文檔,在引發異常時調用ExceptionClear()/ ExceptionDescribe()以外的JNI函數並不「安全」。函數「慢」可能是由編寫調試信息的ExceptionDescribe()函數引起的。

所以,如果我理解這個正確的,這應該是一個乖巧的函數拋出一個異常,第一時間出現錯誤,並在每個後續調用返回NULL(直到「錯誤」被清除):

if (error != ERROR) { 
    jbyteArray javaArray = env->NewByteArray((jsize) message.size); 
    env->SetByteArrayRegion(javaArray, 0, message.size, reinterpret_cast<jbyte*>(message.buffer())); 
    if (env->ExceptionOccurred()) { 
     error = ERROR; 
     return 0; 
    } 
    return javaArray; 
} else { 
    return env->NewGlobalRef(NULL); 
} 

再次,這是未經測試的,因爲我目前沒有JNI環境。

3

這是一個老問題,但我有太一分鐘前...

你說你的問題:

return 0; // Does NOT work - doesn't crash, just slows everything down horrible. 

我只是給了一個嘗試實際上,與jintArray,因爲這是我的代碼必須分配和返回,除非發生錯誤(由與本主題無關的某些標準定義),在這種情況下,它必須返回空結果。

碰巧返回NULL(定義爲((void*)0))完美的作品,並解釋爲null當回Java端。我沒有注意到任何表演的退化。除非我錯過任何返回0而沒有void *強制轉換不會改變任何事情。

所以我不認爲這是你遇到的放緩的原因。 NULL看起來很好,返回null

編輯

  • 我不確認,則返回值無關演出。我只測試了一邊返回空值的相同代碼,而另一邊則返回一個對象(一個jintArray)。性能與NULL,大小爲0的jintArray和靜態分配的幾KB的隨機jintArray類似。

  • 我也嘗試改變一個調用者類的字段的值,並且返回void和大致相同的性能。慢得多,可能是由於捕獲該字段並設置它所需的反射代碼。

  • 所有這些測試都是在Android下進行的,而不是在Java standalones下進行的 - 也許這是爲什麼? (見註釋):HAXM下運行

    • 的API 17 x86模擬器
    • 的API 19之一,在相同的條件
    • 兩個API 19物理設備下運行 - 華碩片劑和銀河5 - 運行在Dalvik下。