当调用本地方法时,JVM需要做什么?

22

当调用一个声明为native的Java方法时,JVM运行时通常需要执行哪些步骤?

HotSpot 1.8.0 JVM如何实现JNI函数调用?有哪些检查步骤(例如返回后未处理的异常)?JVM需要执行哪些簿记工作(例如本地引用注册表)?在调用本地Java方法后控制流程将转到何处?如果有人能够提供来自本地HotSpot 1.8.0代码的入口点或重要方法,我也将不胜感激。

免责声明:我知道我可以自己阅读代码,但先前的解释有助于快速找到代码的路径。此外,我发现这个问题值得被谷歌搜索。

1个回答

47
从Java调用JNI方法与简单的C函数调用相比较而言,代价更高。 HotSpot通常执行以下大部分步骤来调用JNI方法:
1. 创建堆栈帧。 2. 根据ABI将参数移动到适当的寄存器或堆栈位置。 3. 将对象引用包装成JNI句柄。 4. 获取静态方法的JNIEnv*和jclass,并将它们作为附加参数传递。 5. 检查是否应该调用method_entry跟踪函数。 6. 如果方法是同步的,则锁定对象监视器。 7. 检查本机函数是否已链接。函数查找和链接是惰性执行的。 8. 从in_java状态切换线程到in_native状态。 9. 调用本机函数 10. 检查是否需要安全点。 11. 将线程返回到in_java状态。 12. 如果已锁定,则解锁监视器。 13. 通知method_exit。 14. 取消包装对象结果并重置JNI句柄块。 15. 处理JNI异常。 16. 删除堆栈帧。
这个过程的源代码可以在SharedRuntime::generate_native_wrapper中找到。
正如你所看到的,开销可能很大。但是,在许多情况下,上述步骤大多数是不必要的。例如,如果本地方法只对字节数组执行一些编码/解码操作,既不会抛出任何异常,也不会调用其他JNI函数。对于这些情况,HotSpot有一个非标准(且不为人知)的约定称为“关键本地方法”,在here中进行了讨论。

你漏掉了一些。在调用方法之前固定参数对象,然后在调用后取消固定。弹出任何推送的帧,并在方法返回后释放由该方法创建的任何本地引用。 - user207421
@EJP 您所说的固定参数对象是什么意思?HotSpot不支持传统意义上的对象固定。实际上没有本地引用被"释放"。JVM通过两个机器指令重置整个JNI句柄块(我已经提到了这一点),并且任何创建的本地JNI引用都会自动变成垃圾。 - apangin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接