理解JVM运行时数据区(四)本地方法栈

2,024 阅读5分钟

前言

前面我们讲解了运行时数据区里面的程序计数器Java虚拟机栈,接下来这篇文章,我们将对线程私有区域里面的最后一个数据区域 —— 本地方法栈做一个讲解。

什么是本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈所发挥的作用是非常相似的,其区别是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。

《Java虚拟机规范》中对本地方法栈中方法使用的语言、使用方法与数据结构并没有任何强制规定,因此具体的虚拟机可以根据需要自行实现它,甚至有的Java虚拟机(如HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。

什么是本地方法

简单来说,在Java程序上,本地方法是非java语言实现的方法,我们可以看个例子:这是我们常用的Thread里面的一个本地方法。

image.png 可以看到这个方法使用了native来修饰,并且没有方法体,这样的定义方式有点类似抽象方法和接口方法,但也仅是定义方式类似。本地方法的实现是使用非Java语言在外部实现的。

本地方法的方法体是使用非Java语言实现的,如C语言,具体由JVM底层实现去支持。他的作用是融合不同的编程语言为Java使用,最初的设计初衷是融合C/C++语言。Java程序存在一些需要与底层系统(如操作系统或某些硬件)进行数据交互,而通过本地方法,我们可以实现在java层面与底层系统进行交互

这边还有一种说法时:在Java诞生的时候,编程语言是C语言的天下,很多工具都是使用C语言开发实现,为了能发展壮大,一方面是吸引C语言的编程工具人加入Java的怀抱,另一方面是为了能快速使用C语言编写的底层库,因此设计定义了这种方式。

当然,不管是什么说法,实际上本地方法大家都是有必要了解的,特别是Android攻城狮,最近这几年,不管是音视频还是物联网,都会使用到本地方法。

为什么使用本地方法

Java使用起来很方便,然而Java代码有一定的局限性,有时候不能和系统底层交互,或是追求程序的效率时。这时候就需要更加底层的语言和更快的运行效率。

  • 方便与Java之外的环境交互,如与操作系统或某些硬件交换信息,本地方法为我们提供了一个非常简洁的接口,而且我们无需去了解Java应用之外的繁琐的细节。
  • 虚拟机本来就是由C++写的,一些操作系统特性JVM没有封装提供出来,那我们就可以自行使用C语言来实现它,并通过本地方法来调用。
  • 最求更快的运行效率

本地方法栈的特点

  • Java虚拟机栈管理Java方法的调用,而本地方法栈用于管理本地方法的调用。
  • 本地方法栈也是线程私有的。
  • 允许被实现成固定或者是可动态扩展的内存大小(在内存溢出方面是相同的)。
  • 如果线程请求分配的栈空间超过本地方法栈允许的最大容量,Java虚拟机将会抛出一个StackOverflowError异常。
  • 如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么Java虚拟机将会抛出一个OutOfMemoryError异常。
  • 本地方法是使用C语言实现的。
  • 它的具体做法是在本地方法栈中登记native方法,在执行引擎执行时加载本地方法库。

image.png

  • 当某个线程调用一个本地方法时,它就进入了一个全新的并且不再受虚拟机限制的世界。他和虚拟机拥有同样的权限。
  • 本地方法可以通过本地方法接口来访问虚拟机内部的运行时数据区。
  • 它甚至可以直接使用本地处理器中的寄存器。
  • 直接从本地内存堆中分配任意数量的内存。

现状

目前对于后端Java开发人员来说,本地方法使用的场景越来越少了,比如通过Java程序驱动打印机或者Java系统管理生产设备,在企业级应用中已经比较少见了。因为基于现在编程技术的发展,可选的通信交互方式也越来越多,比如可以使用Socket通信,也可以使用Web Service等等。这边就不多做介绍了。

结束语

通过上面的的介绍,我们对本地方法栈有了更深一点的了解,当然由于本人对本地方法的使用比较少,没办法再更深层次的讲解。对于文中的描述,如果有错误的地方,欢迎大家在评论区指出,我们一起来探讨。

系列文章