在了解这部分之前,首先需要了解,什么是本地方法
本地方法
Native Method 是一个 Java 调用非 Java 代码的接口,该方法的具体实现由非 Java 语言实现。比如说 C。 这种处理逻辑,不难推理出,这并不是 Java 的特色,其他的语言中也是有类似机制的。 例如: C 中,用 extern “C” 来让 C 编译器去调用一个 C 的函数。
原文解释如下
"A native method is a Java method whose implementation is provided by non-java code."
主要作用
Java 环境交互
Java 应用与 Java 外面的环境交互,这是本地方法存在的主要原因。例如,当 Java 需要和一些底层系统,类似 操作系统或者某些硬件交换信息时,本地方法正是这样一种交流机制:其为我们提供了简洁的接口,我们无需去了解 Java 应用之外的繁琐的细节。
操作系统交互
JVM 支持着 Java 语言的运行,尽管其包含了 解释器与一些连接到本地代码的库组成,但依然不能忽略其不是一个完整的系统的事实。并且其还是经常依赖于底层系统的支持。这些底层常常是操作系统,通过使用本地方法,就可以一哦那个 Java 实现了 jre 与底层的交互,甚至 JVM 的一部分其实本就是用 C 写的。并且如果我们要使用一些 Java 语言本身没有提供的封装的系统特性时,也需要使用本地方法。
主角-本地方法栈
可以这样想, Java 虚拟机栈用于管理 Java 方法的调用,本地方法栈(Native Method Stack)用于管理本地方法的调用。
线程私有,可以被允许实现成固定或者可动态扩展的内存大小。
如果线程请求分配的栈容量超过本地方法栈允许的最大容量,Java虚拟机将会抛出一个 stackoverflowError 异常。 如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么Java虚拟机将会抛出一个outofMemoryError 异常。
具体逻辑
本地方法是用 C 来实现的,具体做法:
在 Native Method Stack 中登记 native 方法,在 Execution Engine 执行时加载本地方法库。
当某个线程在调用一个本地方法时,就进入了一个全新且不再受虚拟机限制的领域,其和虚拟机拥有同样的权限。
特性:
- 本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区
- 可直接使用本地处理器中的寄存器
- 从本地内存的堆中分配任意数量的内存
❕ 并不是所有非 JVM 都支持本地方法,如果产品不打算支持 native 方法,可以无需实现本地方法栈。并且在 Hotspot JVM 中,直接将本地方法栈和虚拟机栈合在了一起。
Native 方法
Native 方法是 Java 通过 JNI 直接调用本地 C/C 库,Native 方法相当于 C/C 暴露给 Java 的一个接口,Java 通过这个接口调用 C/C 方法。当线程调用 Java 方法时,虚拟机会创建一个栈帧并且压入 Java 虚拟机栈。然而当其调用的是 native 方法时,虚拟机会保持 Java 虚拟机栈不变,也不会向 Java 虚拟机栈中压入新栈帧,虚拟机只是简单的动态连接并且直接调用指定的 native 方法。
- 本地方法栈是一个后入先出(Last In First Out)栈。
- 由于是线程私有的,生命周期随着线程,线程启动而产生,线程结束而消亡。
- 本地方法栈会抛出 StackOverflowError 和 OutOfMemoryError 异常。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!