假設我有一個包含N個元素的C字符串數組。我的目標是使用JNI將該數組傳遞給Java函數,並返回一個等長的新字符串數組回到C空間。目前我做如下:將C字符串數組移動到Java空間的更有效方法
- 使用NewObjectArray以產生長度爲N
- 調用NewStringUTF/SetObjectArray N倍的Java對象陣列,至框每個單獨的C字符串到Java對象陣列。
- 調用copyStrArr(下面的源代碼)。
- 用malloc分配長度爲N的(char *)數組。
- 調用GetObjectArrayElement/GetStringUTFChars N次,以從返回的Java Object數組中解開每個單獨的Java String。
僅供參考,Java代碼看起來是這樣的:
public static String[] copyStrArr(String []inArr)
{
String []outArr = new String[inArr.length];
for(int _i = 0; _i < outArr.length; _i++) {
outArr[_i] = inArr[_i]; /* Normally real work would be done here */
}
return outArr;
}
在「真實」的情況下,實際的工作將裏面的for循環來完成,但對於標杆,我們要做的僅僅是副本數據。
對於較大的N值,這很慢。不敬虔緩慢。當從C到Java移動類似大小的整數或雙精度數組並返回時,它的運行速度比String []大約快70倍。大約99.5%的時間花在裝箱和拆箱數據上。在原始情況下,JNI提供了{Set,Get} ArrayRegion函數,可以將原始數組從C空間批量複製到Java空間並返回,速度更快。
有人建議我使用byte []作爲中介,將數據導入Java空間,然後在Java中進行單獨的String對象裝箱(JVM可以優化事物)。基準測試表明,這比原來的測試表現稍差,將大部分開銷轉移到Java。部分原因可能是我可能無法在Java中以最優方式拆箱/裝箱byte []。我做如下:
- 分配一個充分大的字節[]與NewByteArray
- 調用SetByteArrayRegion N次來填充字節[]
- 調用copyBytArray(下面源)
- 調用GetByteArrayRegion和複製整個結果返回C空間
- 分配一個足夠大的數組(char *)
- 將N個字符串中的每一個從結果中複製到新分配的數組中。
我的Java代碼如下所示:
public static byte[] copyBytArr(byte []inArr)
{
String[] tokInArr = new String(inArr, UTF8_CHARSET).split("\0");
String []tokOutArr = new String[tokInArr.length];
int len = 0;
for(int _i = 0; _i < tokOutArr.length; _i++) {
tokOutArr[_i] = tokInArr[_i]; /* Normally real work would be done here */
len += (tokInArr[_i].length() + 1);
}
byte[] outArr = new byte[len];
int _j = 0;
for(int _i = 0; _i < tokOutArr.length; _i++) {
byte[] bytes = tokOutArr[_i].getBytes(UTF8_CHARSET);
for(int _k = 0; _k < bytes.length; _k++) {
outArr[_j++] = bytes[_k];
}
outArr[_j++] = '\0';
}
return outArr;
}
在這個測試的開銷約55%是在Java中度過的,其餘的則花在裝箱/拆箱。
有人提出我的一些開銷與我在C中使用UTF-8數據有關,因爲Java使用UTF-16。這是不可避免的。
有沒有人有任何想法,我可能會更有效地去做這件事?
移動大量數據總是很慢,並且在JNI邊界上移動任何東西都很慢。你真的必須這樣做嗎? – EJP
可以用char或其他東西代替String對象嗎?因爲原始類型處理速度比JVM中的對象更快 – user4127
@Radiodef我不希望我的名字與任何'JNI中沒有任何內容是有效的'聲明相關聯。無效的是將數據移動到JNI邊界,這是因爲它*是*數據移動。如果您使用100%Java或100%C,則不必移動任何東西。 JNI中的大部分內容都非常高效,在某些情況下效率也很高,因爲沒有錯誤檢查。 – EJP