前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java底层-执行引擎

Java底层-执行引擎

作者头像
每天学Java
发布2020-07-15 15:12:09
1.2K0
发布2020-07-15 15:12:09
举报
文章被收录于专栏:每天学Java每天学Java

上一节我们谈到运行时数据区的区域是如何划分的,以及划分的每一块区域作用。运行时速数据区功能从名字中就大致能看出来:存储运行数据,那么在虚拟机中程序存储的区域有了,那么程序执行由谁来负责呢?就是我们这一节要谈论的执行引擎。

先回忆一下前面几节内容:一个.java文件经Javac编译器编译为.class文件(字节码文件), 当我们使用java命令执行该class文件时(HotSpot为例),首先会创建JVM实例,开辟内存空间,然后由类加载器将相应的字节码文件加载到虚拟机内存中,最后找到程序执行入口的main函数, 由JVM创建的main线程调用main函数(线程为执行引擎的的一个实例,并为该线程绑定程序计数器,虚拟机栈),main函数调用的过程中会先创建一个main帧,根据编译时期就已经确定的局部变量数组和操作数栈的大小分配内存空间, 将内存空间清零,将main帧压入main线程虚拟机栈中,main帧执行过程中,如遇到其他方法调用,同样会将调用的方法封装为栈帧压入栈中。

在上面回顾中,我们提及到「由JVM创建的main线程调用main函数」这么一句话,需要注意的是不能认为类加载完成之后main线程才会被创建,因为类加载过程中main线程也有参与的,如下代码将静态代码块是执行的主类中,两次输出都是 Thread[main,5,main]。可见main线程并不是到调用到main函数的时候才创建。

代码语言:javascript
复制
class Test {
    static {
        System.out.println(Thread.currentThread());
    }
    public static void main(String[] args) {
        System.out.println(Thread.currentThread());
    }
}

Java底层-HotSpot一文的开始说到「每一个Java进程都存在一个JVM的实例」,所以JVM实例对应一个独立的Java进程,而在JVM中执行引擎实例则对应了属于运行程序的线程,所以有时候我们会认为线程为执行引擎的的一个实例,这种说法可能并不准确,但是每一个Java线程的运行都会伴随着执行引擎的执行过程

在JVM中执行引擎通常又是如何去执行字节码呢?在我们物理机中,指令的执行建立在cpu、硬件、指令集、操作系统的层面,而在JVM规范中制定了虚拟机字节码执行引擎的概念模型,这个概念模型作为具体的JVM的外观模型(Facade)。而在不同虚拟机实现中,执行字节码通常会有两种执行方式,一种是编译器执行,一种是解释器执行。或者两种方式混合执行,比如HotSpot虚拟机。

编译器执行是先将源代码进行优化转换,形成可执行程序,让机器能够直接执行,这种方式优点是执行效率高,但是这种方式也存在缺点,在优化转换的过程中,目标代码已经和运行机器的CPU架构相匹配,无法跨平台运行。

解释器执行是逐条解释字节码并执行,这种方式是将每一句源代码都要经过解释器解释为可以执行的机器指令,缺点是执行效率会低,但是跨平台的目的可以实现,开发人员不用再考虑每个平台如何去编译,只需要关注代码的编写。

上面我们说到HotSpot是兼容两种执行的,在执行代码过程中会将解释执行与编译执行二者结合起来进行。其中编译执行得益于JIT(即时编译器),它会将热点代码进行编译放入缓存,这样对于热点代码的执行效率和编译型语言基本上完全相等了。

知道了HotSpot虚拟机的执行引擎如何执行程序之后,我们思考下执行程序在哪里呢?上面我们说过线程的运行都会伴随这执行引擎执行的过程,而线程需要执行的方法都存储在虚拟机栈中,而执行引擎需要执行程序就是当前虚拟机栈的栈顶栈帧,在上一节谈及虚拟机栈的时候我们谈过栈帧(Stack Frame),栈帧是保存方法信息的地方,是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。

每一个栈帧都包括了局部变量表、操作数栈、动态连接、方法返回地址和一些额外的附加信息。在编译程序代码的时候,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写入到方法表的 Code 属性之中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。一个线程中的方法调用链可能会很长,很多方法都同时处于执行状态。对于执行引擎来说,在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧(Current Stack Frame),与这个栈帧相关联的方法称为当前方法(Current Method)。

执行引擎运行的所有字节码指令都只针对当前栈帧进行操作

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 每天学Java 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档