Java 是否使用 JNI "out-of-the-box"?

Does Java use JNI "out-of-the-box"?

我在概念上不清楚 Java 何时使用 JNI。文献 1,2 似乎建议使用 JNI 是可选的 - 它对我自己的现有本机 C 应用程序来说是一个有用的功能,但最好尽可能避免使用它: 亮表示"Remember that once an application uses the JNI, it risks losing two benefits [of portability and security]".

但是,我查看了 Oracle 在 SDK 中的 API 实现,我在 java/lang/System.java 中看到了 public static native void arraycopy。问题:

  1. 这样标记的方法在本机中不使用 JNI 吗?
  2. 在进行系统调用时Java不使用JNI吗?

任何 Java API 实现都需要系统调用,所以如果我是对的,似乎无法避免与本机代码交互。

1:霍斯特曼,核心 Java 第 2 卷
2. Liang,Java™ Native Interface Programmer's Guide and Specification

  1. Don't methods marked as such, in native, use JNI?

是的,就是这个意思。

  1. Doesn't Java make use JNI when making system calls?

同样的问题。只有本地方法可以调用系统调用,所以Java代码只能通过本地方法调用系统调用。

使用 JNI 是可选的对于应用程序。它对于 JVM 是必不可少的。

您列出了 JNI 的两个缺点 - 可移植性安全性。实际上,还有一个在日常生活中更为重要的问题:JNI 调用会带来显着的性能成本,因为它们会影响全局 JVM 状态并锁定一些 JVM 功能,包括 GC。

中所述,JVM 确实依赖于 JNI。但这不是一个完整的答案。

您的 JVM 可能支持快速 JNI 方法(例如 Android ART 支持)。这些方法保证是快速和非阻塞的,并且它们可以在不改变状态的情况下执行,参见例如@FastNative。 Java SDK 本机方法大量使用此类改进,因此它们不会遭受传统 JNI 的 性能 成本。

这些本机方法在 运行 期间不依赖于 LoadLibrary()。这消除了 JNI 的另一个显着性能成本 - 在 运行 时间加载和 'binding' 本机方法。 运行时间绑定的最大风险是它发生在任意时间,由 classloader 决定,并且可能与您的 JVM 或应用程序必须在那个时间做的其他紧急事情发生冲突。与系统本机方法无关。

此外,可移植性 问题无关紧要:Java 运行时间是为每个支持的平台精心设计的,它本身不是 'portable',只有 Java 应用程序 运行ning 在它上面。

最后,安全 JNI 的风险是双重的:JNI 不受 private 声明的限制,本机代码可以做危险的事情危及同一 JVM 中的任何 class 或应用程序 运行ning。而且,从第三方库加载 JNI 代码可能会被黑客攻击(例如,更改 OS 环境足以导致 System.loadLibrary() 加载欺诈者版本的库)。系统本机方法对此类攻击免疫。

简而言之,即使 JVM 确实使用了 JNI,这也不是您自己 classes 随意使用 JNI 的借口。