前言
本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和参考文献请见100个问题搞定Java虚拟机
正文
Java 中 native 方法的底层原理
当在 Java 代码中调用这些 native 方法时,Java 虚拟机将通过 JNI,调用至对应的 C 函数(即 native 方法对应的 C 实现)中。
Java 中的 native 方法的链接方式
一是按照 JNI 的默认规范命名所要链接的 C 函数,并依赖于 Java 虚拟机自动链接。
另一种则是在 C 代码中主动链接。
像 Java 的 C 代码
JNI 提供了一系列 API 来允许 C 代码使用 Java 语言特性。
这些 API 不仅使用了特殊的数据结构来表示 Java 类,还拥有特殊的异常处理模式。
JNI 与引用
JNI 中的引用可分为局部引用和全局引用。
这两者都可以阻止垃圾回收器回收被引用的 Java 对象。
不同的是,局部引用在 native 方法调用返回之后便会失效。
传入参数以及大部分 JNI API 函数的返回值都属于局部引用。
补充
什么情况下需要使用 JNI ?
我们经常会遇见 Java 语言较难表达,甚至是无法表达的应用场景。
比如我们希望使用汇编语言(如 X86_64 的 SIMD 指令)来提升关键代码的性能;
再比如,我们希望调用 Java 核心类库无法提供的,某个体系架构或者操作系统特有的功能。
在这种情况下,我们往往会牺牲可移植性,在 Java 代码中调用 C 代码 (C/C++) 代码,并在其中实现所需功能。
这种跨语言的调用,便需要借助 Java 虚拟机的 Java Native Interface(JNI)机制。
JNI的额外性能开销
1、进入 C 函数时,对引用类型参数的句柄化,和调整参数位置(C 调用和 Java 调用传参的方式不一样)
2、从 C 函数返回时,清理线程私有句柄块
即时编译器可能会将某些指定的本地方法调用给替换掉。这些特定的本地方法叫 intrinsics。
关于 intrinsics 可以参考我的这篇博客——HotSpot虚拟机中的intrinsic是指什么?