java - 使用JNI而不是JNA來調用本機代碼?



4 Answers

很難回答這樣一個通用的問題。 我想最明顯的區別是,在JNI中,類型轉換是在Java /本地邊界的本地端實現的,而在JNA中,類型轉換是用Java實現的。 如果你已經對C編程感到很舒服,並且必須自己實現一些本地代碼,那麼我會認為JNI看起來不太複雜。 如果您是Java程序員,只需調用第三方本機庫,那麼使用JNA可能是避免JNI可能不太明顯的問題的最簡單途徑。

雖然我從來沒有對任何差異進行過基準測試,但由於設計原因,至少假設在某些情況下使用JNA進行類型轉換的性能會比JNI差。 例如,在傳遞數組時,JNA會在每次函數調用開始時將這些數據從Java轉換為本機,並在函數調用結束時返回。 使用JNI,您可以在生成數組的本地“視圖”時控制自己,可能只創建數組一部分的視圖,使視圖跨越幾個函數調用,並在最後釋放視圖並決定是否需要保留更改(可能需要復制數據)或放棄更改(不需要復制)。 我知道你可以通過使用Memory類的JNA跨越函數調用使用本地數組,但是這也需要內存複製,這對於JNI可能是不必要的。 這種差異可能並不相關,但如果您最初的目標是通過在本機代碼中實施部分代碼來提高應用程序性能,那麼使用性能較差的橋接技術似乎並不是最明顯的選擇。

java jni native jna

與JNI相比,JNA似乎更容易使用本地代碼。 你會在哪些情況下使用JNI而不是JNA?




順便說一下,在我們的一個項目中,我們保留了一個非常小的JNI腳印。 我們使用協議緩衝區來表示我們的域對象,因此只有一個本地函數來橋接Java和C(當然C函數會調用一堆其他函數)。




如果您希望獲得JNI性能,但因其複雜性而受到干擾,則可以考慮使用自動生成JNI綁定的工具。 例如, JANET (免責聲明:我寫它)允許您將Java和C ++代碼混合到一個源文件中,例如使用標準Java語法從C ++調用Java。 例如,下面是如何將C字符串打印到Java標準輸出:

native "C++" void printHello() {
    const char* helloWorld = "Hello, World!";
    `System.out.println(#$(helloWorld));`
}

然後JANET將嵌入反引用的Java轉換為適當的JNI調用。




除非我錯過了一些東西,那麼JNA和JNI之間的主要區別是,與JNA無法從本地(C)代碼調用Java代碼?




Related