运行时数据区——Java虚拟机栈

简介:  与程序计数器一样, Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。

 

与程序计数器一样, Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。Java栈以帧为单位保存线程的运行状态。每个方法在执行的时候都会创建一个栈帧用于存储局部变量表、操作栈、动态链接、 方法出口等信息。虚拟机只会直接对Java栈执行两种操作: 以帧为单位的压栈或出栈。

 

Java方法可以以两种方式完成。一种通过return返回,称为正常返回;一种是通过抛出异常而中止的。不管以哪种方式返回,虚拟机都会将当前帧弹出Java栈然后释放掉,这样上一个方法的帧就成为当前帧了。

Java栈上的所有数据都是此线程私有的。任何线程都不能访问另一个线程的栈数据, 因此我们不需要考虑多线程情況下栈数据的访问同步问题。当一个线程调用一个方法时,方法的局部变量保存在调用线程Java栈的帧中 。只有一个线程能总是访问那些局部变量, 即调用方法的线程 。

像方法区和堆一样, Java栈和帧在内存中也不必是连续的 。帧可以分布在连续的栈里,也可以分布在堆里, 或者二者兼而有之。 表示Java栈和栈帧的实际数据结构由虚拟机的实现者决定, 某些实现允许用户指定Java栈的初始大小和最大最小值。

局部变量表

局部变量表存放了编译期可知的各种基本数据类型(boolean、 byte、 char、 short、 int、float、long、 double)、对象引用(reference类型,它不等同于对象本身,根据不同的虚拟机实现, 它可能是一个指向对象起始地址的引用指针, 也可能指向一个代表对象的句柄或者其他与此对象相关的位置) 和 retunAddress类型 (指向了一条字节码指令的地址)。

局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。Java栈帧的局部变量表被组织为一个以字长为单位,从0开始计数的数组。虚拟机通过索引定位的方式使用局部变量表, 编译器首先按声明的顺序把这些参数放入局部变量数组。 字节码指令通过从0开始的索引来使用其中的数据。类型为int、 float、 reference和returnAddress的值在数组中只占据一项, 而类型为byte、 short和char的值在存入数组前都将被转换为int值, 因而同样占据一项。 但是类型为long和double的值在数组中占据连续的两项。

在访问局部变量中的long和double值的时候, 只需取出连续两项中第一项的索引值。 例如某个long值占据第3、 4项, 那么指令会取索引为3的long值。 局部变量区的所有值都是字对齐的, long和double这样占据两项数组元素的值同样可以起始于任何索引 。

下面通过两个例子及图示说明下局部变量区:

public static int runClassMethod(int i,long l,float f,double d,Object o,byte b) { 
   return 0;   
}
public int runInstanceMethod(char c,double d,short s,boolean b) { 
       return 0;   
}

如果是实例方法(非 static的方法), 那么局部变量表中第 0位素引的 Slot默认是用于传递方法所属对象实例的引用, 在方法中可以通过关键字 “this'' 来访问这个隐含的参数。其余参数则按照参数表的顺序来排列,占用从1开始的局部变量Slot。

操作数栈

和局部变量表一样,操作数栈也被组织成一个以字长为单位的数组。可以把操作数栈理解为存储计算时,临时数据的存储区域。虚拟机在操作数栈中存储数据的方式和在局部变量区中是一样的。

但和前者不同,它不是通过索引来访问的,而是通过压栈和出栈来访问的。操作数栈的毎一个元素可以是任意的 Java数据类型, 32位数据类型所占的栈容量为1, 64位数据类型所占的栈容量为2。

Java 虚拟机的指令是从操作数栈中而不是从寄存器中取得, 因此它的运行方式是基于栈的而不是基于寄存器的 。

虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据, 执行运算, 然后把结果压回操作数栈。

动态链接

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

参考:

https://iamjohnnyzhuang.github.io/java/2016/07/12/Java%E5%A0%86%E5%92%8C%E6%A0%88%E7%9C%8B%E8%BF%99%E7%AF%87%E5%B0%B1%E5%A4%9F.html

 

 

 

 

相关文章
|
10月前
|
前端开发 Java 关系型数据库
基于Java+Springboot+Vue开发的鲜花商城管理系统源码+运行
基于Java+Springboot+Vue开发的鲜花商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的鲜花商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。技术学习共同进步
612 7
|
12月前
|
Java 程序员 开发者
Java社招面试题:一个线程运行时发生异常会怎样?
大家好,我是小米。今天分享一个经典的 Java 面试题:线程运行时发生异常,程序会怎样处理?此问题考察 Java 线程和异常处理机制的理解。线程发生异常,默认会导致线程终止,但可以通过 try-catch 捕获并处理,避免影响其他线程。未捕获的异常可通过 Thread.UncaughtExceptionHandler 处理。线程池中的异常会被自动处理,不影响任务执行。希望这篇文章能帮助你深入理解 Java 线程异常处理机制,为面试做好准备。如果你觉得有帮助,欢迎收藏、转发!
705 14
|
12月前
|
前端开发 JavaScript Java
Java打包jar运行时分离lib和jar
在`pom.xml`的`build`节点中,设置`packaging`为`jar`,并配置插件分离依赖库到`lib`目录和资源文件到`resources`目录。这样可以在运行时通过`-Dloader.path=lib,resources`加载外部依赖和资源文件,便于独立升级依赖库和修改资源文件,而无需重新打包程序。具体插件包括`maven-dependency-plugin`、`maven-resources-plugin`和`spring-boot-maven-plugin`等。
757 1
|
Java
jvm复习,深入理解java虚拟机一:运行时数据区域
这篇文章深入探讨了Java虚拟机的运行时数据区域,包括程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、元空间和运行时常量池,并讨论了它们的作用、特点以及与垃圾回收的关系。
228 19
jvm复习,深入理解java虚拟机一:运行时数据区域
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
954 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
存储 SQL 小程序
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
这篇文章详细介绍了Java虚拟机(JVM)的运行时数据区域和JVM指令集,包括程序计数器、虚拟机栈、本地方法栈、直接内存、方法区和堆,以及栈帧的组成部分和执行流程。
325 2
JVM知识体系学习五:Java Runtime Data Area and JVM Instruction (java运行时数据区域和java指令(大约200多条,这里就将一些简单的指令和学习))
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
296 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
|
IDE Java 编译器
Java:如何确定编译和运行时类路径是否一致
类路径(Classpath)是JVM用于查找类文件的路径列表,对编译和运行Java程序至关重要。编译时通过`javac -classpath`指定,运行时通过`java -classpath`指定。IDE如Eclipse和IntelliJ IDEA也提供界面管理类路径。确保编译和运行时类路径一致,特别是外部库和项目内部类的路径设置。
801 5
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
1564 3
|
Java
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!
本文介绍了Java中this和super关键字的用法,包括在构造方法中使用this来区分参数和成员变量、使用super调用父类构造方法和方法,以及它们在同一个方法中同时使用的场景。
660 0
Java关键字 —— super 与 this 详细解释!一看就懂 有代码实例运行!