`

《虚拟机字节码执行引擎》笔记:运行时栈帧结构

阅读更多

周志明先生所著的《深入理解Java虚拟机:JVM高级特性与最佳实践》(购买地址:亚马逊链接),对我学习Java、理解Java之道有非常大的帮助。至今已读过两遍,为了能够融会贯通,加深记忆(人老了记忆力差),便在Blog上记录一些认为该记的东西。

 

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

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

         对于执行引擎来说,活动线程中,只有栈顶的栈帧是有效的,称为当前栈帧(Current Stack Frame),这个栈帧所关联的方法称为当前方法(Current Method)。执行引擎所运行的所有字节码指令都只针对当前栈帧进行操作,栈帧的概念结构如下图:



 

局部变量表

         局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译为class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。

         局部变量表的容量以变量槽(Variable Slot)为最小单位。虚拟机规范中允许Slot的长度随着处理器、操作系统或虚拟机的不同而发生变化。在32位系统中,一个Slot可以存放一个32位以内的数据类型。Java中占用32位以内的数据类型有boolean,byte,char,short,int,float,referencereturnAddress八种。Reference是对象的引用,虚拟机实现至少都应该能从此引用中直接或间接地查找到对象在Java堆中的其实地址索引和方法区中的对象类型数据。returnAddress指向了一条字节码指令的地址。

         对于64位的数据类型(doublelong),虚拟机会以高位在前的方式为其分配两个连续的Slot空间。

         虚拟机通过索引定位的方式使用局部变量表,索引值的范围是从0开始到局部变量表最大的Slot数据。如果是实例方法(非static的方法),那么局部变量表中第0位索引的Slot默认是用于传递方法所属对象实例的引用(关键字this)。其余参数按照参数表的顺序来排序,占用从1开始的局部变量Slot。参数表分配完毕后,再根据方法体内部定义的变量顺序和作用域分配其余Slot

 

         操作数栈

         操作数栈也常被成为操作栈,它是一个LIFO栈。操作数栈的最大深度也在编译的时候被写入到Code属性的max_stacks数据项之中。32位数据类型所占用的栈容量为1 64位数据类型为2

         当一个方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令向操作数栈中写入和提取内容,也就是入栈出栈操作。比如,整数加法的字节码指令iadd在运行的时候要求操作数栈中最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令是,会将这两个int值出栈并相加,然后将相加的结果入栈。

         Java虚拟机的解释执行引擎称为“基于栈的执行引擎”,其中所值的“栈”就是操作数栈。

 

         动态连接

         每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池中指向方法的符号引用为参数。这些符号引用一部分会在类加载阶段或第一次使用的时候转化为直接引用,这种转化称为静态解析。另外一部分将在每一次的运行期间转化为直接引用,这部分称为动态连接。

 

         方法返回地址

         当一个方法被执行后,有两种方式退出这个方法。第一种是执行引擎遇到任意一个方法返回的字节码指令,这时候可能会有返回值传递给上层的方法调用者,是否有返回值和返回值的类型将根据遇到何种方法返回指令来决定,这种退出方法的方式称为正常完成出口(Normal Method Invocation Completion)。

         另一种退出方式是,在方法执行过程中遇到了异常,并且这个异常没有在方法体内得到处理,无论是JVM内部产生的异常,还是用户代码中使用athrow字节码指令产生的异常,只要是本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出,这种退出方法的方式成为异常完成出口(Abrupt Method Invocation Completion),此时不会给它的上层调用者产生任何返回值。

         无论采用何种退出方式,在方法退出后,都需要返回到方法被调用的位置。方法返回时可能需要在栈帧中保存一些信息,用来帮助恢复它的上层方法的执行状态。

 

         方法退出的过程实际上等同于把当前栈帧出栈,因此退出时可能执行的操作有:恢复上层方法的局部变量表和操作数栈,把返回值(如果有的话)压入调用者栈帧的操作数栈中,调整PC计数器的值以指向方法调用指令后面的一条指令等。

  • 大小: 46.6 KB
分享到:
评论

相关推荐

    深入java虚拟机笔记

    - **Java虚拟机(JVM)**:JVM是Java体系的核心组件,负责解释执行Java字节码,同时提供了内存管理、异常处理等运行时服务。它确保了Java程序能够在不同的操作系统上一致地运行。 - **类装载器的体系结构**:类装载...

    理解虚拟机--有笔记版

    程序计数器是一个比较小的内存区域,用于指示当前线程所执行的字节码执行到了第几行,是线程私有的内存。 本地方法栈与栈类似,但服务于JVM运行的本地方法(Native Method)。 在JVM的执行过程中,类加载器(Class...

    JVM的学习笔记PDF版

    5. **字节码执行**:JVM通过解释器将字节码转换为机器码执行,为了提高性能,JVM还实现了Just-In-Time(JIT)编译器,将热点代码编译成本地机器码。 6. **内存调优**:理解和调整JVM内存参数(如-Xms, -Xmx, -Xss等...

    jvm视频及笔记

    Java虚拟机(JVM)是Java程序运行的核心组件,它负责解释和执行字节码,为开发者提供了跨平台的运行环境。"jvm视频及笔记"这个资源显然是一份全面学习JVM的材料,结合了视频教程和书面笔记,帮助学习者深入理解JVM的...

    JVM思维导图,学习思维笔记

    JVM通过类加载器、运行时数据区、执行引擎、本地方法接口和本地方法库等组件协同工作。 二、JVM内存结构 1. 堆(Heap):所有对象实例都在堆中分配内存,是JVM中最大的一块内存区域,且被所有线程共享。堆分为...

    java虚拟机学习笔记基础篇

    当Java程序执行时,通过类加载器加载类,然后JVM的执行引擎会使用解释器逐行解释执行字节码,或者使用即时编译器(JIT)将字节码编译为本地机器码后执行。这样,通过类加载器和执行引擎的配合,Java程序得以运行在...

    jVM学习笔记.ppt

    执行阶段则是由JVM执行引擎解析字节码并执行。这一过程涉及到类加载机制,包括Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader和Custom ClassLoader,它们按照特定的层次关系和加载顺序加载类,确保...

    JVM性能学习笔记思维导图

    - **执行引擎(Execution Engine)**:解析和执行字节码,包含解释器和JIT编译器。 - **垃圾收集器(Garbage Collector)**:自动管理内存,避免内存泄露。 2. **内存区域详解** - **堆(Heap)**:所有对象实例都在堆...

    JVM学习笔记

    - **执行引擎**:负责解释执行或编译执行JVM字节码文件。 #### Java堆 Java堆是JVM中最为重要的内存区域之一,其主要用来存储对象实例。为了提高垃圾回收效率,通常会将堆划分为不同的区域,例如**新生代**和**老...

    JVM成神之路.rar

    3. **执行引擎**:这是JVM的心脏,负责执行字节码。它包括解释器和即时编译器(如HotSpot JVM的C1和C2编译器),能将字节码转换为机器码以提高性能。 4. **垃圾收集器**(GC):Java的一大优势就是自动内存管理。...

    笔记 — JVM内存结构

    JVM由三个主要部分组成:类加载器、执行引擎和运行时数据区域。理解JVM内存结构对于优化Java应用的性能至关重要。 1. **方法区**: - 方法区是JVM内存中的一个重要区域,它存储了已经被加载的类信息,包括常量、...

    JVM-LearningAndOptimize:JVM学习笔记与调优实战

    JVM包括类加载器、运行时数据区、执行引擎、本地方法接口和垃圾收集器等核心组件。 二、类加载机制 JVM的类加载器按照双亲委派模型工作,确保类的唯一性。加载过程包括加载、验证、准备、解析和初始化五个阶段,每...

Global site tag (gtag.js) - Google Analytics