前言:本文所讨论的内容基于 hotspot 虚拟机
Java的native方法
什么是Java的native方法?
native方法,不是由Java语言去实现的,而是通过第三方语言,如C语言实现方法内容,Java调用C语言实现的方法去和底层的操作系统沟通。
Java的native方法是怎么和jvm之间形成沟通和联系的?
我们从逻辑推断,Java的native方法,必定是和jvm的真正实现native方法的C方法是一一对应关系,当我们调用Java native方法时,如线程的相关的方法 sleep、start等,实际上,是jvm去调用C方法,去和操作系统交流沟通,从而实际的操作线程。
不饶圈子,JAVA一些类(Class Object System等)的静态代码块,也就是static修饰的代码块,都有一个注册函数 registerNatives,用来注册Java native方法和 JVM中 native方法的C实现建立一一对应关系。registerNatives方法在静态代码块,说明在类准备阶段,就已经完成这项工作,也就是说 ,这某些类尚未完成初始化之前,该类的native方法尚未和Java native方法的实际实现建立关系,是不可用的。
在jvm里面,有一个method的数据结构,用来存储Java方法入口,而这个methods结构后的第一个内存槽,用来存储native方法入口,native方法入口不包含于method数据结构,只是位置固定在其后面。
所谓注册,解释Java将native 方法和 native 方法 实际实现对应的C方法 设置对应入口地址。
Java 通过JNI 接口调用 Java native方法,实际是jvm调用 InterperterRuntime :: prepare_native_call方法,很明显,Interperter 解释器 runtime 运行时,也就是在运行时,来解析native方法调用的字节码,这方法去到method后面的第一个槽,找到对应的native方法并返回,如果此时对应的native方法没找到,会生成一个很长的调用链,继续寻找和初始化等,不是本文所要叙述的内容,暂省略。
当jvm调用了native方法的实现后,此时,要把结果再反馈给Java方法。
那么jvm又是怎么反馈结果给Java方法呢?
实际是通过JavaCalls::call_help方法,方法参数包含了,Java普通方法的入口地址和一些参数,而Java方法的入口地址,就是之前所说的method数据结构。
call_help方法会跳转到 call_stub_entry方法,该方法会检查Java方法的参数,和编译等等,然后生成Java栈,并跳转到entry_point方法,entry_point方法创建解释器栈,并最终通过 dispatch_next 解释执行一条条Java方法逻辑的字节码。
补充说明,call_stub_entry和entry_point的内容都是早先jvm初始化时,生成的机器指令集。
call_stub_entry是由虚拟机初始化时 generate_call_stub方法生成,entry_point则是由generate_normal_entry方法生成。
以上就是 Java 通过JNI调用 native 方法的执行过程,然后将结果作为参数到Java方法,Java方法再执行相关逻辑的字节码的过程。