簡體   English   中英

將C字符串數組移動到Java空間的更有效方法

[英]A more efficient way of moving an array of C strings into Java space

假設我有一個包含N個元素的C字符串數組。 我的目標是使用JNI將該數組傳遞給Java函數,並將相等長度的新字符串數組返回給C空間。 目前,我正在執行以下操作:

  • 使用NewObjectArray生成長度為N的Java對象數組。
  • N次調用NewStringUTF / SetObjectArray,以將每個單獨的C字符串裝箱到Java Object數組中。
  • 調用copyStrArr(以下來源)。
  • 用malloc分配長度為(char *)的N個數組。
  • 調用N次GetObjectArrayElement / GetStringUTFChars,以從返回的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,這很慢。 太慢了。 當將大小相似的int或double數組從C移到Java並返回Java時,它的運行速度比String []情況快70倍。 將數據裝箱和拆箱的時間大約占99.5%。 在原始情況下,JNI提供了{Set,Get} ArrayRegion函數來將原始數組從C空間批量復制到Java空間,然后再復制回Java空間,這要快得多。

有人建議我使用byte []作為中介,將數據放入Java空間,然后在Java中進行單獨的String Object裝箱(JVM可以在其中進行優化)。 基准測試表明,此方法比原始測試的性能稍差,將大量開銷轉移到了Java中。 部分原因可能是我可能沒有最佳地對Java中的byte []取消裝箱/裝箱。 我正在執行以下操作:

  • 用NewByteArray分配足夠大的byte []
  • 調用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。 這是不可避免的。

有人對我如何更有效地解決這個問題有任何想法嗎?

我認為您的問題是分配了許多字符串對象。 為了獲得真正的性能,您只需要交換大的byte []並使用Wrapper類“指向”字節數組進行String處理。 只要您通過C chars []來回創建字符串對象,就不會獲得真正的吞吐量。

FST正在與“ StructString”類進行類似的操作,以對byte []數據進行操作,而無需創建“真實”對象。

為了進一步加快數據交換的速度,您可能需要使用內存映射文件創建共享內存,然后通過Unsafe或ByteBuffers進行訪問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM