本地方法接口
什么是本地方法?
简单来讲,一个native method就是一个java调用非java代码的接口,该方法的底层实现是非java代码,比如c语言代码,在定义一个native method时,并不提供实现体,像是定义一个接口,native可以和其他java标识符连用,但是abstract除外。
为什么要使用本机方法接口?
虽然java使用起来很方便,但是有些层次的任务不容易用java语言实现,或者我们对运行效率很在意时就有了以下一些问题:
-
与java环境外交互
这是本地方法存在的主要原因,当我们需要和操作系统,硬件交换信息时,本地方法正是这样一种交流机制,他为我们提供一个非常简洁的接口,我们无需去关注java以外的繁琐实现细节。
- Sun解释器使用C实现的,这使得他能像一些普通的C一样与外部交互。jre大部分是由java实现的,但它也通过一些本地方法与外界交互。例如:类java.lang.Thread的setPriority()方法使用java实现的,但它其实是调用该类中的本地方法setPriority().
执行引擎
概述:
- jvm的主要任务是负责将会java编译为字节码文件转载到其内部,但字节码不能直接运行在操作系统之上,因为字节码指令不是机器指令,它只能被jvm锁识别,如果想要让一个java程序运行起来,执行引擎的任务就是将字节码指令解释/编译为对应平台的本地机器指令才可以,它充当了将高级语言翻译成机器语言的翻译者。
什么是解释器?什么是JIT编译器?
- 解释器:当 Java 虚拟机启动时会根据预定义的规范对字节码采用逐行解释的方式执行,将每条字节码文件中的内容“翻译”为对应平台的本地机器指令执行。
- JIT(Just In Time Compiler)编译器:就是虚拟机将源码一次性直接编译为和本地机器平台相关的机器语言,但并不是立即执行。
为什么java是半编译半解释型语言?
JVM 设计者们的初衷仅仅只是单纯地为了满足 Java 程序实现跨平台特性,因此避免采用静态编译的方式由高级语言直接生成本地机器指令,从而诞生了实现解释器在运行时采用逐行解释字节码执行程序的想法。
解释器真正意义上所承担的角色就是一个运行时“翻译者”,将字节码文件中的内容“翻译”为对应平台的本地机器指令执行,执行效率低。
JIT 编译器将字节码翻译成本地代码后,就可以做一个缓存操作,存储在方法区的 JIT 代码缓存中(执行效率更高了)。是否需要启动 JIT 编译器将字节码直接编译为对应平台的本地机器指令,则需要根据代码被调用执行的频率而定。JIT 编译器在运行时会针对那些频繁被调用的“热点代码”做出深度优化,将其直接编译为对应平台的本地机器指令,以此提升 Java 程序的执行性能。
目前 HotSpot VM 所采用的热点探测方式是基于计数器的热点探测。
JIT 编译器执行效率高为什么还需要解释器?
当程序启动时,解释器会马上发挥作用,响应速度快,省去了编译的时间。而编译器想要发挥作用,需要把代码编译为机器码,需要一定的执行时间,但编译后的代码执行效率高,所以让这两者并存,来换取一个平衡点。
执行引擎和程序计数器、操作数栈、局部变量表的关系
操作数栈具体做什么:
- 存储方法执行过程中的操作数和中间结果。当方法执行时,其局部变量和操作数栈是该方法执行过程中的工作区域,用于临时存储数据和计算结果。
- 用于方法的参数传递和返回值。方法调用时,实参会被压入操作数栈,而返回值则从操作数栈中弹出。
程序计数器:程序计数器是每个线程私有的,用于记录当前线程正在执行的字节码指令位置。执行引擎根据程序计数器中的指令位置从方法的字节码中读取指令,然后根据指令操作数从局部变量表和操作数栈中取出数据执行。
序计数器中的指令位置从方法的字节码中读取指令,然后根据指令操作数从局部变量表和操作数栈中取出数据执行。
局部变量表和操作数栈是栈帧中用于存储方法执行过程中数据的重要部分,执行引擎根据程序计数器中的指令位置从字节码中读取指令,并根据指令操作数从局部变量表和操作数栈中取出数据执行相应操作,从而实现了方法的执行和程序的运行。