JVM 中的 returnAddress过程详解

 更新时间:2022年04月29日 09:21:57   作者:m0_67402013  
JVM的毕竟是个虚拟机,是一种规范,虽说符合冯诺依曼的计算机设计理念,但是他并不是实体计算机,所以他的组成也不是什么存储器,控制器,运算 器,输入输出设备,本文给大家介绍JVM 中的 returnAddress,感兴趣的朋友一起看看吧

JVM是虚拟机,也是一种规范,他遵循着冯·诺依曼体系结构的设计原理。冯·诺依曼体系结构中,指出计算机处理的数据和指令都是二进制数,采用存储 程序方式不加区分的存储在同一个存储器里,并且顺序执行,指令由操作码和地址码组成,操作码决定了操作类型和所操作的数的数字类型,地址码则指出地址码和 操作数。从dos到window8,从unix到ubuntu和CentOS,还有MAC OS等等,不同的操作系统指令集以及数据结构都有着差异,而JVM通过在操作系统上建立虚拟机,自己定义出来的一套统一的数据结构和操作指令,把同一套语 言翻译给各大主流的操作系统,实现了跨平台运行,可以说JVM是java的核心,是java可以一次编译到处运行的本质所在。

参考文档:jvms12

数据类型

在 JVM 中,数据分为两大类:primitive types (原生类型)和 reference types(引用类型)。

引用类型,让 JVM 能更好的支持于面向对象语言的设计,引用类型的值用来指向内存中分配的类实例或者数组。JVM 规范中并没有详细规定引用类型的实现细节,比如引用应该通过何种方式去定位、访问堆中的对象,具体的对象访问方式取决于虚拟机的具体实现,比如 HotSpot 有其自己的实现方案。

目前主流的访问方式有使用句柄和直接指针两种:

其中使用直接指针访问的方式,类似于 C++ 中的虚表(虚表就是指向对象类型数据的指针)。这两种对象访问方式各有优劣,使用句柄访问的最大好处就是 reference 中存储的是稳定的句柄地址,在对象被移动(比如垃圾回收时,整理内存空间,会移动对象的存储位置)时只会改变句柄中示例数据的指针,而 reference 本身不需要修改。

使用直接指针访问的最大好处就是速度更快,节省了一次内存寻址的时间开销。

原生数据类型包括:numeric types, boolean type, returnAddress type。其中 returnAddress 数据只存在于字节码层面,与编程语言无关,也就是说,我们在 Java 语言中是不会直接与 returnAddress 类型的数据打交道的。

returnAddress 类型的值是指向字节码的指针,不管是物理机还是虚拟机,运行时内存中的数据总归可分为两类:代码,数据。对于冯诺依曼结构的计算机,指令数据和数值数据都存储在内存中,而哈弗结构的计算机,将程序指令与数据分开存储。

对于 JVM 来说,程序就是存储在方法区的字节码指令,而 returnAddress 类型的值就是指向特定指令内存地址的指针。

JVM支持多线程,每个线程有自己的程序计数器(pc register),而 pc 中的值就是当前指令所在的内存地址,即 returnAddress 类型的数据,当线程执行 native 方法时,pc 中的值为 undefined。

栈帧

栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构,栈帧中存储了方法的局部变量表,操作数栈,动态连接,和方法返回地址等信息。在程序编译时,栈帧中需要多大的局部变量表,多深的操作数栈都已经完全确定了,并且写在方法表的 Code 属性中。

当一个方法开始执行后,只有两种方式可以退出,第一种方式是执行引擎遇到任意一个方法返回的字节码指令,这种方式称为正常完成出口;另外一种退出方式是,在方法执行过程中遇到异常,且该异常没有被被捕获,称为异常完成出口。

无论是哪种退出方式,在方法退出后,都需要返回到该方法被调用的位置(地址),让程序继续执行。一般来说,方法执行前,会保存调用者当前的 PC 计数器中的值,当方法正常退出时,将该 PC 计数器的值会作为返回地址,返回给调用者。在方法异常退出时,返回地址是通过异常处理器表来确定的。

方法退出的过程实际上就等于把当前栈帧出栈,一般过程为:

  • 恢复上层方法的局部变量表和操作数栈
  • 把返回值压入调用者栈帧的操作数栈中
  • 调整 PC 计数器的值,以指向方法调用指令后面的一条指令

到此这篇关于JVM 中的 returnAddress的文章就介绍到这了,更多相关JVM returnAddress内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis之#{}与${}的区别使用详解

    Mybatis之#{}与${}的区别使用详解

    这篇文章主要介绍了Mybatis之#{}与${}的区别详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • RocketMq同组消费者如何自动设置InstanceName

    RocketMq同组消费者如何自动设置InstanceName

    这篇文章主要介绍了RocketMq同组消费者如何自动设置InstanceName问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06
  • Java Web基于Session的登录实现方法

    Java Web基于Session的登录实现方法

    这篇文章主要介绍了Java Web基于Session的登录实现方法,涉及Java针对session的操作及表单提交与验证技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-10-10
  • 使用Java SDK实现离线签名

    使用Java SDK实现离线签名

    这篇文章主要介绍了使用Java SDK实现离线签名,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • Java中Static关键字的五种用法详解

    Java中Static关键字的五种用法详解

    这篇文章主要介绍了Java中static的五种用法:修饰成员变量,修饰成员方法,修饰内部类,静态代码块,静态导包,想详细了解的小伙伴可以参考阅读本文
    2023-03-03
  • Maven里面没有plugins dependence问题解决

    Maven里面没有plugins dependence问题解决

    在整合Nacos和Dubbo时,出现Maven错误可以通过检查父模块的依赖解决,问题源于MySQL驱动版本不兼容,移除特定依赖并刷新pom文件可恢复项目,执行clean命令,查看报错,感兴趣的可以了解一下
    2024-10-10
  • Springboot整合log4j2日志全解总结

    Springboot整合log4j2日志全解总结

    这篇文章主要介绍了Springboot整合log4j2日志全解总结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • java计算两个日期中间的时间

    java计算两个日期中间的时间

    这篇文章主要介绍了java计算两个日期中间的时间的相关资料,需要的朋友可以参考下
    2017-04-04
  • 深入浅出RocketMQ的事务消息

    深入浅出RocketMQ的事务消息

    RocketMQ事务消息(Transactional Message)是指应用本地事务和发送消息操作可以被定义到全局事务中,要么同时成功,要么同时失败。本文主要介绍了RocketMQ事务消息的相关知识,需要的可以参考一下
    2023-04-04
  • SpringBoot执行定时任务@Scheduled的方法

    SpringBoot执行定时任务@Scheduled的方法

    这篇文章主要介绍了SpringBoot执行定时任务@Scheduled的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07

最新评论