使用 JNI 而不是 JNA 来调用本机代码?

2022-08-31 09:02:38

与 JNI 相比,JNA 似乎更容易用于调用本机代码。在什么情况下你会使用JNI而不是JNA?


答案 1
  1. JNA不支持c++类的映射,所以如果你使用的是c++库,你需要一个jni包装器。
  2. 如果您需要大量内存复制。例如,您调用一个返回大字节缓冲区的方法,更改其中的某些内容,然后需要调用另一个使用此字节缓冲区的方法。这将需要您将此缓冲区从 c 复制到 java,然后将其从 java 复制回 c。在这种情况下,jni 将在性能方面获胜,因为您可以在 c 中保留和修改此缓冲区,而无需复制。

这些是我遇到的问题。也许还有更多。但一般来说,jna和jni之间的性能并没有太大的不同,所以只要你可以使用JNA,就使用它。

编辑

这个答案似乎很受欢迎。所以这里有一些补充:

  1. 如果你需要映射C++或COM,有一个由JNAerator的创建者Oliver Chafic创建的库,称为BridJ。它仍然是一个年轻的图书馆,但它有许多有趣的功能:
    • Dynamic C / C++ / COM互操作:调用C++方法,创建C++对象(以及来自Java的子类C++类!
    • 直接的类型映射,充分利用泛型(包括更好的指针模型)
    • 完全支持 JNAerator
    • 适用于Windows,Linux,MacOS X,Solaris,Android
  2. 至于内存复制,我相信JNA支持直接字节缓冲器,因此可以避免内存复制。

所以,我仍然相信,只要有可能,最好使用JNA或BridJ,如果性能至关重要,则恢复到jni,因为如果您需要频繁调用本机函数,性能下降是显而易见的。


答案 2

很难回答这样一个笼统的问题。我认为最明显的区别是,使用JNI,类型转换是在Java/native边界的本机端实现的,而对于JNA,类型转换是在Java中实现的。如果你已经对用C语言编程感到很舒服,并且必须自己实现一些原生代码,我会认为JNI看起来不会太复杂。如果你是一个Java程序员,只需要调用第三方的原生库,那么使用JNA可能是避免JNI可能不那么明显的问题的最简单方法。

虽然我从来没有对任何差异进行过基准测试,但由于设计的原因,至少假设在某些情况下使用JNA进行类型转换的性能会比使用JNI更差。例如,在传递数组时,JNA 会在每次函数调用开始时将这些数组从 Java 转换为本机,并在函数调用结束时将其转换回。使用 JNI,您可以控制何时生成数组的本机“视图”,可能只创建数组一部分的视图,在多个函数调用中保留视图,并在最后释放视图,并决定是要保留更改(可能需要将数据复制回来)还是放弃更改(不需要复制)。我知道您可以使用 Memory 类跨 JNA 的函数调用使用本机数组,但这也需要内存复制,这对于 JNI 来说可能是不必要的。这种差异可能无关紧要,但是如果您最初的目标是通过在本机代码中实现部分应用程序来提高应用程序性能,那么使用性能较差的桥接技术似乎不是最明显的选择。


推荐