zoukankan      html  css  js  c++  java
  • 原创 | jvm02、java虚拟机栈

    小白带你快速了解!

    java虚拟机栈是jvm内存结构中的一员,也就是我们平常所说的栈内存,它是线程私有的,每个线程都有属于自己的一个java虚拟机栈,java虚拟机栈的生命周期和线程相同,也就是说当一个线程开始了,也就产生了一个java虚拟机栈。

    既然是栈,肯定有个什么玩意入栈和出栈,java虚拟机栈主要是用来存放线程运行方法时所需的数据,指令和方法返回地址等,那么靠什么存储?这就需要栈帧,这么个意思

    在这里插入图片描述

    当你一个线程开始了,你就必须给我来个java虚拟机栈,我要存储数据啊,靠什么存储?栈帧啊,存储什么数据呢?运行方法所需的数据啊,所以栈帧的产生必须是一个方法被调用了,也就是说,线程开始,有了一个java虚拟机栈,当一个方法被调用,就产生一个栈帧用来存放运行这个方法所需的一些数据,一个方法从被调用到结束就对应一个栈帧从入栈到出栈的过程,可以得知,栈帧是和方法息息相关的。这个栈帧包含这么些东西。

    1. 局部变量表
    2. 操作数栈
    3. 动态链接
    4. 方法返回地址

    如果你想深入了解请继续往下看!

    庆哥陪你深入分析!

    以上小白为大家介绍了什么是java虚拟机栈,我这里总结一下

    1. java虚拟机栈线程私有,随线程开始而产生。
    2. java虚拟机栈主要靠方法被调用的时候产生的栈帧来存放数据。
    3. 栈帧随一个方法被调用而产生
    4. 一个方法从被调用到结束就对应栈帧在java虚拟机栈中入栈和出栈的过程。

    我们之前常说,基本数据类型是保存在栈内存中的,现在要知道的是这是根据时期而定的,因为如果你单单理解基本数据类型是存放在栈内存的时候,当你遇到运行时常量池的时候你一定会迷,为啥,运行时常量池也是存放基本数据类型啊,那到底谁存放呢?

    这就要根据时期来说了。当你编写一个java文件,被编译成class文件之后,这个class文件中就产生了一个class文件常量池,当被加载到内存中的时候,这个class文件常量池就成了运行时常量池,当然,运行时常量池包含的东西要多点,这时候基本数据类型也是存放在这个运行时常量池的。

    但是,你要注意了,这个时候并没有什么线程开始和方法调用,所以也就没有什么栈帧来存放数据,只有当你的方法被调用的时候,才会产生一个栈帧来存放数据,这时候就会存放基本数据类型的数据,而我猜想这些数据也是从运行时常量池拿来的。那么栈帧中是如何操作的呢?其实栈帧也分为这么几个部分

    1. 局部变量表
    2. 操作数栈
    3. 动态链接
    4. 方法返回地址

    而我们说的基本类型存放在栈内存,更加准确的说就是存放在栈帧中的,这里有一张图

    在这里插入图片描述

    大家注意了,图中底色淡黄色的描述目前应该是错误的,这里我也有疑问就是,比如int a = 66这句代码是如何存储的,这个66是存放在局部变量还是这个a是存放在局部变量,我们之前也说,基本数据类型和对象引用是存放在栈内存的,那么比如String s = new String()中,s叫做对象引用,这个s是存放在哪里?在局部变量中吗?

    以上是我不理解的地方,如果谁对这块比较熟悉,还请不耐烦的教我一下,这里我请教了@刘欣和@黄俊还有@小猴子三位前辈大佬,奈何我资质愚钝,还是不怎么理解,唉!辛苦三位前辈了。我私下会再做研究!

    另外关于类变量和局部变量有这么一个区别,对基本数据类型来说,对于类变量(static)和全局变量,如果不显式地对其赋值而直接使用,则系统会为其赋予默认的零值,而对于局部变量来说,在使用前必须显式地为其赋值,否则编译时不通过。

    这个栈帧中除了局部变量表之外还有操作数栈,动态链接和方法返回地址。那什么是操作数栈呢?在《深入理解java虚拟机》中有这么一段话“整数加法的字节码指令iadd在运行的时候操作数栈中最接近栈顶的两个元素已经存入了两个int型的数值,当执行这个指令时,会将这两个int值出栈并相加,然后将相加的结果入栈。”也就是说操作数栈也是存储数据的区域。

    每一个栈帧中都会有这么一个引用,这个引用存放在运行时常量池中,这个引用指向该栈帧,这个引用的目的是为了支持方法调用过程中的动态链接。符号引用在类加载阶段或者第一次使用阶段会直接转换为直接引用,这个叫做静态解析,还有的是在每一次运行期间转化为直接引用,这部分就称为动态链接。

    方法的退出也就意味着栈帧从java虚拟机栈中出栈,方法的退出一般有两种,一种是正常退出,一种是异常退出,但是,无论是以哪种方式退出,最终都要返回到方法调用的地方,如果是正常退出的话,那么这个返回地址就是调用者的程序计数器的值,如果是异常退出的话,返回地址是由异常处理器表决定的。

    以上为大家浅显的介绍了java虚拟机栈的一些相关知识点,其中关于局部变量表那块自己也不是很明白,真的是想的脑壳疼!

    今天就先到这,我的问题也在文中提出来了,如果你理解的比较透彻,可以教教我,万分感谢,我会继续研究,后续会继续分享!大家是如何理解的,欢迎留言啊!

    脑壳疼。。。写这篇文章的时候也请教了不少人,在此一并感谢!

    待续。。。

  • 相关阅读:
    【Azure 应用服务】在Azure App Service多实例的情况下,如何在应用中通过代码获取到实例名(Instance ID)呢?
    【Azure 应用服务】App Service For Windows 中如何设置代理实现前端静态文件和后端Java Spring Boot Jar包
    【Azure Developer】使用Azure Key Vault 的Key签名后,离线验证的一些参考资料
    【Azure Function】调试 VS Code Javascript Function本地不能运行,报错 Value cannot be null. (Parameter 'provider')问题
    【Azure 应用服务】App Service 使用Tomcat运行Java应用,如何设置前端网页缓存的相应参数呢(Xms512m Xmx1204m)?
    【Azure API 管理】APIM添加Logtoeventhub的策略后,一些相关APIM与Event Hub的问题
    【Azure API 管理】为调用APIM的请求启用Trace 调试APIM Policy的利器
    【Azure 事件中心】China Azure上是否有Kafka服务简答
    【Azure 应用服务】探索在Azure上设置禁止任何人访问App Service的默认域名(Default URL)
    【Azure 微服务】记一次错误的更新Service Fabric 证书而引发的集群崩溃而只能重建
  • 原文地址:https://www.cnblogs.com/ithuangqing/p/12113639.html
Copyright © 2011-2022 走看看