备案 控制台
开发者社区 数据库 文章 正文

JVM-虚拟机栈详解 ,手画详图,带你快速理解!!!

简介: JVM-虚拟机栈详解 ,手画详图,带你快速理解!!!

微信截图_20220523202233.png

受多种情况的影响,又开始看JVM 方面的知识。


1、Java 实在过于内卷,没法不往深了学。


2、面试题问的多,被迫学习。


3、纯粹的好奇。 很喜欢一句话:“八小时内谋生活,八小时外谋发展。


--- 望别日与君相见时,君已有所成。共勉



封面地点:湖南邵阳


作者:博主🤸‍♂️🤸‍♂️🤸‍♂️


一、虚拟机栈概述


先给大家来看一下 运行时数据区的图示👇


微信截图_20220523202402.png


如果大家没咋了解Java的内存结构,就常会粗粒度地将JVM中的内存区理解为仅有Java堆(heap)和Java战(stack)?为什么?🤳🧐


首先栈是运行时的单位,而堆是存储的单位


  • 栈解决程序的运行问题,即程序如何执行,或者说如何处理数据。


  • 堆解决的是数据存储的问题,即数据怎么放,放哪里


不过今天我们讨论的是虚拟机栈。堆的文章之后才更👨‍💻。


虚拟机栈:java虚拟机栈是线程私有的,他与线程的声明周期同步。虚拟机栈描述的是java方法执行的内存模型,每个方法执行都会创建一个栈帧,栈帧包含局部变量表、操作数栈、动态连接、方法出口等。


注意:🏂


  1. 它的执行速度仅次于程序计数器


  1. 对于栈来说不存在垃圾回收问题


  1. 主管Java程序的运行,它保存方法的局部变量、部分结果,并参与方法的调用和返回。


二、栈帧


2.1、栈与栈桢:


每一个方法的执行到执行完成,对应着一个栈帧在虚拟机中从入栈到出栈的过程。  👨‍🚀 1、java虚拟机栈栈顶的栈帧就是当前执行方法的栈帧,PC寄存器会指向该地址。👇 2、当这个方法调用其他方法的时候就会创建一个新的栈帧,这个新的栈帧会被方法Java虚拟机栈的栈顶变为当前的活动栈,在当前只有当前活动栈的本地变量才能被使用, 3、当这个栈帧所有指令都完成的时候,这个栈帧被移除,之前的栈帧变为活动栈,前面移除栈帧的返回值变为这个栈帧的一个操作数。


2.2、栈帧概述


微信截图_20220523202457.png


栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区的虚拟机栈(Virtual Machine Stack)的栈元素。每个栈帧都包含了:


  1. 局部变量表


  1. 操作数栈(或表达式栈)


  1. 动态连接 (或指向运行时常量池的方法引用)


  1. 方法返回地址(或方法正常退出或者异常退出的定义)


  1. 一些额外的附加信息


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


如下图:


微信截图_20220523202533.png


左边是通过javap -v 类名的.class 命令反编译出来的。==注意啊,得在生成目标文件夹目录下👇==


我们通过上图可以看到,在编译过程中,已经给每个栈桢分配好了 操作数栈 的深度啊,局部变量表的大小等等。


局部变量表是4的原因:虽然我们在这个方法中只定义了a,b,c 三个局部变量,但是大家还记得 this吗,你没有想错,确实在这个局部变量表中,第一个是this。更深层次解释不了,技术不够。😂。到局部变量部分带大家一起看。


在这里插一句哈,如果大家不熟悉这种命令行去反编译的话,在这里介绍一个idea 的插件。


放心哈,那插件作者肯定没给我打钱,我是感觉真的挺可的,对于我们新手学习这方面。


名字:  jclasslib Bytecode Viewer


微信截图_20220523202603.png


用法


我们将一个类编译完后,兄弟们,编译没有问题吧。不行,感觉还是要贴出来哈。


微信截图_20220523202625.png


编译完成之后。我们打开 菜单中 -->view 选项。


微信截图_20220523202650.png


里面的具体的东东靠大家慢慢发掘了哈,我们还是回归正文啦。==给大家个Oracle 的 JVM 官方规范。方便指令的查找解释哈。==


2.3、想一想我们遇到过哪些与栈相关的异常?


Java 虚拟机规范允许Java栈的大小是动态的或者是固定不变的。 🏄‍♂️


1、如果采用固定大小的Java虚拟机栈,那每一个线程的Java虚拟机栈容量可以在线程创建的时候独立选定。如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量,Java虚拟机将会抛出一个``StackoverflowError `异常。(栈溢出)


举个栗子:相信大家肯定学过递归算法,如果它一直没有出口,结果就是栈溢出。🚣‍♂️


微信截图_20220523202718.png


2、如果Java虚拟机栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的虚拟机栈,那Java虚拟机将会抛出一个 OutOfMemoryError 异常。(也就是内存溢出异常OOM)


微信截图_20220523202838.png


2.4、设置栈内存大小


刚刚大家也看到了,我们可以使用参数 -Xss选项来设置线程的最大栈空间,栈的大小直接决定了函数调用的最大可达深度。


-Xss1m  // m 是Mb
-Xss1k  // k 是Kb


2.5、局部变量表


概述:


局部变量表:Local Variables,被称之为局部变量数组或本地变量表。定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量这些数据类型包括各类基本数据类型、对象引用(reference),以及returnAddress类型。局部变量表是线程私有的。


局部变量表所需的容量大小是在编译期确定下来的,并保存在方法的Code属性的maximum local variables数据项中。在方法运行期间是不会改变局部变量表的大小的。


局部变量表中的变量只在当前方法调用中有效。在方法执行时,虚拟机通过使用局部变量表完成参数值到参数变量列表的传递过程。当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。


👨‍💻👨‍🚀🤹‍♂️🤽‍♂️🏌️‍♂️🐱‍🚀🐱‍🐉🎊🧬🚀🛫🚢🛸🚤⛲🌈🌊 悄咪咪试一波小表情,课间休息会,怕看疲惫了,就放弃继续看下去啦哈。🤗


局部变量的存放 Slot(变量槽)


参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束。🤭


局部变量表,最基本的存储单元是Slot(变量槽)局部变量表中存放编译期可知的各种基本数据类型(8种),引用类型(reference),returnAddress类型的变量。


在局部变量表里,32位以内的类型只占用一个slot(包括returnAddress类型),64位的类型(long和double)占用两个slot。


JVM会为局部变量表中的每一个Slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值。


微信截图_20220523203155.png


静态变量与局部变量的对比


变量的分类:😜


  • 按数据类型分:基本数据类型、引用数据类型


  • 按类中声明的位置分:成员变量(类变量,实例变量)、局部变量


  • 类变量:linking的paper阶段,给类变量默认赋值,init阶段给类变量显示赋值即静态代码块


  • 实例变量:随着对象创建,会在堆空间中分配实例变量空间,并进行默认赋值


  • 局部变量:在使用前必须进行显式赋值,不然编译不通过。


🎅


我们知道类变量表有两次初始化的机会,第一次是在“准备阶段”,执行系统初始化,对类变量设置零值,另一次则是在“初始化”阶段,赋予程序员在代码中定义的初始值。


类变量初始化不同的是,局部变量表不存在系统初始化的过程。这意味着如果创建了局部变量,并且在使用前不对它进行显示赋值,那么将无法通过编译。


微信截图_20220523203239.png


在栈帧中,与性能调优关系最为密切的部分就是前面提到的局部变量表。在方法执行时,虚拟机使用局部变量表完成方法的传递。 🛀局部变量表中的变量也是重要的垃圾回收根节点,只要被局部变量表中直接或间接引用的对象都不会被回收


2.6、操作数栈


1、每一个独立的栈帧除了包含局部变量表以外,还包含一个后进先出(Last - In - First -Out)的 操作数栈,也可以称之为 表达式栈(Expression Stack)🤪


操作数栈,在方法执行过程中,根据字节码指令,往栈中写入数据或提取数据,即入栈(push)和 出栈(pop)


  • 某些字节码指令将值压入操作数栈,其余的字节码指令将操作数取出栈。使用它们后再把结果压入栈


  • 比如:执行复制、交换、求和等操作


🤦‍♂️ 2、操作数栈,主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。


3、每一个操作数栈都会拥有一个明确的栈深度用于存储数值,其所需的最大深度在编译期就定义好了,保存在方法的Code属性中,为maxstack的值。


4、操作数栈的每一个元素可以是任意Java数据类型,32位的数据类型占一个栈容量,64位的数据类型占2个栈容量,且在方法执行的任意时刻,操作数栈的深度都不会超过max_stacks中设置的最大值。


5、操作数栈并非采用访问索引的方式来进行数据访问的,而是只能通过标准的入栈和出栈操作来完成一次数据访问


6、如果被调用的方法带有返回值的话,其返回值将会被压入当前栈帧的操作数栈中,并更新PC寄存器中下一条需要执行的字节码指令。


public void stackTest() {
    int a = 10;
    int b = 21;
    int c = a + b;
}


0 bipush 10 // 10被压入操作数堆栈。 
 2 istore_1  //从操作数堆栈中弹出一个数 ,将这个数赋值给局部变量 a  这里istore_的索引之所以是一,而不是0,是因为局部变量表中,第一个放进去的是this。 static方法中 没有 this,那个时候索引才是从0开始。
 3 bipush 21
 5 istore_2 // 同上
 6 iload_1  // iload_<n>  <n > 必须是当前帧的局部变量数组的索引。< n >处的局部变量必须包含一个int. < n >处的局部变量的值被压入操作数堆栈。
 7 iload_2
 8 iadd // 执行 add 操作
 9 istore_3 // 将结果赋值到局部变量 索引为3的变量上。
10 return


微信截图_20220523203336.png


我想看完这个gif动图 ,我想大家大概能够明白操作数栈是一个什么样的流程了吧,或者已经明白了吧。如果没有明白的话,可以留言评论哈。


2.7、动态链接


概述


动态链接(Dynamic Linking): 每个栈帧都保存了 一个 可以指向当前方法所在类的 运行时常量池, 目的是: 当前方法中如果需要调用其他方法的时候, 能够从运行时常量池中找到对应的符号引用, 然后将符号引用转换为直接引用,然后就能直接调用对应方法, 这就是动态链接。 比如:invokedynamic指令 👍


在Java源文件被编译到字节码文件中时,所有的变量和方法引用都作为符号引用(symbolic Reference)保存在class文件的常量池里。


小思考:为什么需要运行时常量池?


因为在不同的方法,都可能调用常量或者方法,所以只需要存储一份即可,节省了空间。


常量池的作用:就是为了提供一些符号和常量,便于指令的识别


比如:描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。


讲这么这么多,没有亲眼见过,其实还是会对所谓的动态链接感到陌生的,因为我也是的,所以接下来👇 给大家举了栗子和图哦。


1、代码部分


微信截图_20220523203413.png


2、通过 javap -v 类名.class 进行反编译后


  • main 方法

微信截图_20220523203444.png


  • 描述一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的


  • 注意图中 调用test  方法中的那一行指令 invokevirtual #6                  // Method test:()V


  • invokevirtual #6 :调用实例方法;基于类调度  。


  • 那么#6是什么意思呢? 这就牵扯到了常量池啦。


  • 我们接着来看一下 常量池(Constant pool)


  • 微信截图_20220523203552.png
  • #6  又接着指向了 #4.#33  但其实 # 6 后面的注释已经讲出来了。//

StackFrameTest.test:()V


  • #4 是  Class,   StackFrameTest 实例。


  • #33 又接着执行#15:#9  也就是后面的注解  // test:() V


  • test 说的是方法名    ()V 说的返回值是 void。


链接


静态链接:


当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期克制,且运行期保持不变时,这种情况下降调用方法的符号引用转换为直接引用的过程称之为静态链接


动态链接:


如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用的方法的符号转换为直接引用,由于这种引用转换过程具备动态性,因此也被称之为动态链接。


这个动态链接只从粗略的角度讲了,里面其实还有一些内容没讲,考虑到篇幅过长,有时间会再补一篇动态链接的文章。


2.8、方法返回地址


存放调用该方法的pc寄存器的值。当一个方法开始执行后,只有两种方式可以退出这个方法:


  • 正常完成出口:执行引擎遇到任意一个方法返回的字节码指令(return),会有返回值传递给上层的方法调用者,简称正常完成出口;究竟需要使用哪一个返回指令,还需要根据方法返回值的实际数据类型而定。


  • 异常完成出口 :在方法执行过程中遇到异常(Exception),并且这个异常没有在方法内进行处理,也就是只要在本方法的异常表中没有搜索到匹配的异常处理器,就会导致方法退出,简称异常完成出口。


无论通过哪种方式退出,在方法退出后都返回到该方法被调用的位置。方法正常退出时,调用者的pc计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址。而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。


异常表:


方法执行过程中,抛出异常时的异常处理,存储在一个异常处理表,方便在发生异常的时候找到处理异常的代码


微信截图_20220523203715.png


本质上,方法的退出就是当前栈帧出栈的过程。此时,需要恢复上层方法的局部变量表、操作数栈、将返回值压入调用者栈帧的操作数栈、设置PC寄存器值等,让调用者方法继续执行下去。


正常完成出口和异常完成出口的区别在于:通过异常完成出口退出的不会给他的上层调用者产生任何的返回值


2.9、一些附加信息


栈帧中还允许携带与Java虚拟机实现相关的一些附加信息。例如:对程序调试提供支持的信息。


课间休息会哈 接着看题啦


微信截图_20220523203745.png


面试


面试提问:

1、这个栈内存大小是设置的越大越好吗????是的话,是为什么?不是的话,又是为什么?


  • 不是,一定时间内降低了OOM概率,但是会挤占其它的线程空间,因为整个空间是有限的。


2、垃圾回收是否涉及到虚拟机栈?


  • 不会


3、方法中定义的局部变量是否线程安全?


  • 具体问题具体分析。看到这一点你可能会产生一些疑惑,我也理解。


  • 为什么会产生疑惑呢?我讲过局部变量表是线程私有的,竟然都是私有的,肯定是线程安全的啊,但是这有一个前提的,如果这个局部变量在方法内部产生,又在方法内部消亡,生命周期是和栈桢相同的,那么可以肯定是它是线程安全的。但是如果这个方法是需要接收参数,或者是需要返回值,那么这个时候就可以需要具体分析啦。


自言自语


兄弟们,还是一起躺平吧。内卷太累辣吧。。。 👩‍💻->👨‍💻🛌🛌


宁在春
目录
相关文章
西兰花加满
|
4天前
|
存储 安全 Java
深入探究Java虚拟机(JVM)的技术细节
深入探究Java虚拟机(JVM)的技术细节
西兰花加满
5 0
肥猪肥猪-17824
|
5天前
|
存储 算法 Java
深入理解Java虚拟机(JVM)的垃圾回收机制
【5月更文挑战第30天】 在Java开发领域,垃圾回收(Garbage Collection, GC)是确保应用程序性能和内存效率的关键因素。本文将深入探讨Java虚拟机(JVM)的垃圾回收机制,解析其工作原理、不同算法的特点以及如何通过调优来提高应用性能。我们将透过JVM的内存结构,探索垃圾回收过程中涉及的关键技术点,并讨论现代Java应用中常见的垃圾回收器实现。
肥猪肥猪-17824
12 1
肥猪肥猪-17824
|
7天前
|
存储 Java 开发者
深入理解Java虚拟机:JVM内存模型解析
【5月更文挑战第27天】 在Java程序的运行过程中,JVM(Java Virtual Machine)扮演着至关重要的角色。作为Java语言的核心执行环境,JVM不仅负责代码的执行,还管理着程序运行时的内存分配与回收。本文将深入探讨JVM的内存模型,包括其结构、各部分的作用以及它们之间的相互关系。通过对JVM内存模型的剖析,我们能够更好地理解Java程序的性能特征,并针对性地进行调优,从而提升应用的执行效率和稳定性。
肥猪肥猪-17824
22 0
叶落闲庭
|
8天前
|
Oracle Cloud Native Java
【JVM】初步认识Java虚拟机
【JVM】初步认识Java虚拟机
叶落闲庭
22 6
敏叔V587
|
6天前
|
Java Linux
JVM堆内存诊断
JVM堆内存诊断
敏叔V587
12 0
Mr.anla
|
10天前
|
存储 Java 对象存储
JVM(内存区域划分)
JVM(内存区域划分)
Mr.anla
27 1
菜菜的后端私房菜
|
20天前
|
存储 缓存 算法
深入浅出JVM(二)之运行时数据区和内存溢出异常
深入浅出JVM(二)之运行时数据区和内存溢出异常
菜菜的后端私房菜
27 0
终有链响
|
5天前
|
存储 算法 Java
JVM性能调优:内存模型及垃圾收集算法
JVM性能调优:内存模型及垃圾收集算法
终有链响
12 0
敏叔V587
|
6天前
|
存储 安全 Java
浅谈JVM内存结构
浅谈JVM内存结构
敏叔V587
10 0
Sessy
|
8天前
|
Java
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配...
<Java SE> 5道递归计算,创建数组,数组遍历,JVM内存分配
Sessy
34 2

热门文章

最新文章

  • 1
    VMware Workstation 在此主机上不支持嵌套虚拟化。模块“MonitorMode”启动失败。未能启动虚拟机。
  • 2
    虚拟机字节码执行引擎
  • 3
    烂泥:KVM虚拟机克隆
  • 4
    解决无法打开虚拟机的方法
  • 5
    openNebula 运维系列虚拟机virtual machines operations
  • 6
    Hyper-V 3 虚拟机快照之三 应用和删除快照
  • 7
    安装Vmware workstation虚拟机(含软件和注册码)
  • 8
    操作系统就是虚拟机--主内又主外
  • 9
    linux kvm虚拟机配置及常见问题处理
  • 10
    调整vmware虚拟机硬盘空间大小
  • 1
    深入剖析JVM内存管理与对象创建原理
    53
  • 2
    JDK、JRE 和 JVM 的区别和联系
    131
  • 3
    深入理解Java虚拟机:类加载机制
    17
  • 4
    【JVM】深入理解JVM对象内存分配方式
    35
  • 5
    【JVM】了解JVM中动态判断对象年龄的原理
    30
  • 6
    【JVM】分代收集算法:提升Java垃圾回收效率
    34
  • 7
    【JVM】深入了解JVM方法区
    29
  • 8
    【JVM】深入理解Java引用类型:强引用、软引用、弱引用和虚引用
    192
  • 9
    【JVM】Java堆 :深入理解内存中的对象世界
    68
  • 10
    【JVM】Java虚拟机栈(Java Virtual Machine Stacks)
    39
  • 相关课程

    更多
  • Java 虚拟机原理
  • 相关电子书

    更多
  • 基于英特尔 SSD 的虚拟机缓存解决SSD
  • JVM的GC
  • 基于JVM的脚本语言开发、运用实践
  • 下一篇
    2024年阿里云免费云服务器及学生云服务器申请教程参考

    深圳SEO优化公司广元网站优化公司邯郸建站公司甘孜优秀网站设计多少钱海北外贸网站制作揭阳网站优化按天收费毕节网站优化排名推荐云浮网站设计模板多少钱哈密百度网站优化排名衢州SEO按天扣费南山网站排名优化哪家好鸡西建网站推荐天门设计网站多少钱那曲百度seo哪家好聊城网站建设设计多少钱济南网络营销推荐娄底设计公司网站报价廊坊百姓网标王桐城企业网站建设价格永新模板推广哪家好抚州至尊标王多少钱玉树至尊标王四平网站优化按天收费哪家好外贸网站设计报价来宾企业网站建设推荐濮阳网站改版价格扬州优化公司漳州高端网站设计公司海东网络营销推荐黄南网站优化推广公司安阳百度关键词包年推广哪家好歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

    深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化