第五篇 虚拟机字节码执行引擎

来源:互联网 发布:淘宝买什么产品好 编辑:程序博客网 时间:2024/06/06 03:17

概述:

        执行引擎是java虚拟机最核心的组成部分之一,“虚拟机”是一个相对于“物理机”的概念,区别是:物理机的执行引擎是直接建立在处理器、硬件、指令集和操作系统层面的;而虚拟机的执行引擎则是自己实现的,因此可以自行制定指令集与引擎的结构体系,并且能够执行那些不被硬件直接支持的指令集格式。本篇主要从概念的角度来学习虚拟机的方法调用和字节码执行。

第一节:运行时的栈帧结构

        栈帧是用于支持虚拟机进行方法调度和方法执行的数据结构,它是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用开始到执行完成的过程,就对应着一个栈帧在虚拟机栈里面从入栈到出栈的过程。

        在编译程序代码的时候,栈帧中需要多大的局部变量表、多深的操作数栈都已经完全确定了,并且写入到方法表的Code属性之中,因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于虚拟机实现。

        对于执行引擎来说,活动线程中,只有栈顶的栈帧是有效的,称为当前栈帧,这个栈帧所关联的方法称为当前方法。


        接下来详细学习栈帧中的各个元素:

1、局部变量表

      局部变量表用于存储方法参数和方法内部定义的局部变量。

      局部变量表的容量以变量槽(Slot)为最小单位,虚拟机规范中并没有指明Slot具体是多大,一般来说,每个Slot占用32位长度的内存空间。虚拟机允许Slot的长度随着处理器、操作系统或虚拟机的不同而发生变化。不过无论如何,即使在64位虚拟机中使用了64位长度的内存空间来实现一个Slot,虚拟机仍要使用对齐和补白的手段将Slot在外观上看起来与32位虚拟机中的一致。

        说起数据类型,java中的32位以内的数据类型有:boolean,byte,char,short,int,float,reference和returnAddress八种类型,其中returnAddress类型指的是为字节码指令jsr,jsr_w和ret服务的,它指向了一条字节码指令的地址。64位的只有long和double,对32位的分配一个空间,对64位的分配两个空间。

        关于局部变量表,还有一点需要强调,就是局部变量表不想前面介绍的类变量那样存在“准备阶段”。我们知道,类变量在准备阶段赋予系统初始值;另外一次在初始化阶段,赋予程序定义的初始值。但是局部变量不一样,局部变量没有“准备阶段”,不赋初值的话在编译阶段就会报错。

2、操作数栈

       在一个方法执行的时候,操作数栈是空的,在方法的执行过程中,会有各种字节码指令向操作数栈中写入和提取内容,也就是入栈和出栈操作。

       注意:我们前面说过每个线程都有各自独立的栈帧,他们是互相独立的;但大多虚拟机的实现都会做一些优化处理,让栈帧中的一部分内容实现共享。

一般:操作数栈共享区域和局部变量表共享区域是重叠区域。

3、动态连接

        每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。

4、方法返回地址

         当一个方法执行完后会有两种返回方式:

         (1)正常返回:返回一定数值或是返回空,执行调用该方法的方法;

         (2)异常返回:返回时出现异常,退出时,返回地址要通过异常处理器来确定,栈帧中一般不会保存这部分信息。

第二节:方法调用(解析和分配:查阅资料即可)

         调用阶段: 该阶段唯一确定的就是调用哪一个方法,即确定调用方法的版本。

第三节:基于栈的字节码解释执行引擎

         我们强调过,执行java代码的时候有解释执行和编译执行,这个不强调了,编译课程上老师强调过。

         

我们需要知道的是:javac编译器完成了程序代码经过词法分析、语法分析到抽象语树,在遍历语法树生成线性的字节码指令流的过程。因为这一部分是在虚拟机外进行的,而解释器在虚拟机的内部,所以java程序的编译就是半独立的实现。

基于寄存器或是栈的 解释执行器的原理学习计算机体系结构就可以了。

0 0
原创粉丝点击