JVM学习笔记(3)—— 运行时数据区—— 程序计数器、虚拟机栈、本地方法栈

news2024/9/27 9:28:18

程序计数器、虚拟机栈、本地方法栈都是线程私有的,jvm中每个线程都有一份

一、程序计数器

JVM中的程序计数器是一个与PC寄存器功能类似的逻辑结构,用于记录当前线程要执行的下一条jvm指令的地址,解释器读取到对应的jvm指令后将其翻译成机器指令交给CPU去执行,并在程序计数器中更新下一条jvm指令的地址。

程序计数器是运行时唯一不会发生内存溢出的区域。

二、虚拟机栈

虚拟机栈是运行时的单位,而堆是存储的单位
即:栈是解决程序的运行问题,即程序如何执行。而堆解决的是数据存储的问题,即数据怎么放,放在哪

每个线程在创建时都会创建一个虚拟机栈,线程运行时每调用一个方法都会生成一个对应的栈帧压入栈,方法执行结束(正常return或内部抛出异常)则出栈,并将结果返回给前一个栈帧,使前一个栈帧成为当前活动栈帧,直到所有栈帧全部出栈,则线程执行结束,栈也同时销毁。虚拟机栈是线程私有的,生命周期和线程一致。
在这里插入图片描述

1. 栈帧的内部结构

需要注意的是,栈帧中并不存储方法的代码指令,方法的字节码指令是存储在方法区对应类的类信息的对应方法信息中(具体就是在方法Code属性表的code属性值中),是所有线程共享的,栈帧中存储的是执行构成方法的一组指令所需的信息,分为以下五个部分

(1)局部变量表

局部变量表定义为一个数组,基本存储单元称为局部变量槽(Slot),用于存放 方法参数和方法内定义的局部变量 \color{red}{方法参数和方法内定义的局部变量} 方法参数和方法内定义的局部变量,数据类型包括8类基本数据类型、对象引用和returnAddress类型(指向了一条字节码指令的地址),其中64位长度的long和double类型数据占用两个变量槽,其他类型占用一个。如果当前帧是由构造方法或者实例方法创建的,那么其局部变量表索引为0的slot处会存放其对象的this引用,其余参数按顺序继续排列。

局部变量表的大小在编译期就确定下来了,存储在方法Code属性表的max_locals属性中,当进入一个方法时,其栈帧的局部变量表所分配的内存空间是完全确定的,运行过程中也不会改变其大小。
在这里插入图片描述

因此我们可以很容易从另一个角度理解为什么在static方法中不能使用this指针,因为其局部变量表中就没有对象的this引用

注意,并不是在方法中用了多少个局部变量,就把这些局部变量所占变量槽数量之和作为max_locals的值,操作数栈和局部变量表直接决定一个该方法的栈帧所耗费的内存,不必要的操作数栈深度和变量槽数量会造成内存的浪费。Java虚拟机的做法是将局部变量表中的变量槽进行重用,当代码执行超出一个局部变量的作用域时,这个局部变量所占的变量槽可以被其他局部变量所使用,Javac编译器会根据变量的作用域来分配变量槽给各个变量使用,根据同时生存的最大局部变量数量和类型计算出max_locals的大小。
比如方法中if代码块或者for代码块中定义的变量,其作用域只在代码块内,代码块执行结束后,其占用的变量槽就可以被后续定义的变量占用
复用示例:
在这里插入图片描述
如下为从class文件中解析出的test4()方法的局部变量表模板信息,可以看到,表索引位置0要存储对象引用this,而b和c在局部变量表中的索引位置序号是一样的,因为在程序执行时c会复用已销毁的b占用的slot位置
在这里插入图片描述

(2)操作数栈

我们说Java虚拟机的解释引擎是基于栈的执行引擎,其中的栈就是指的操作数栈。操作数栈是数组实现的栈结构,用于解释引擎执行方法字节码指令过程中数据的临时存放和取出。

如下方法的字节码指令,push指令(前面的符号表示数据类型)用于将数据压入栈中,store指令用于出栈一个数据并将其存储到局部变量表指定索引位置(命令后面的数字),load指令用于将局部变量表指定索引位置数据加载到栈中,add命令用于从栈中出栈两个数据相加后将结果压入栈中。如果当前方法有返回值,则方法执行结束后将返回值压入到前一个栈帧的操作数栈中。

在这里插入图片描述
和局部变量表一样,操作数栈的大小也是在编译期确定的,存储在方法Code属性表的max_stack属性值中,为方法执行过程中栈的最大深度,如上图中方法操作数栈最大深度为2。

注意,局部变量表和操作数栈都是在栈帧创建时就分配了固定的空间,但是方法运行前其中都是没有数据的(this引用和参数除外),而是随着方法指令一步一步执行填充数据的

练习:从字节码指令说清Java自增原理(i++, ++i)

(3)动态链接信息

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

(4)方法返回地址

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

方法中catch的异常,会存储在方法的异常处理表中,如果方法不是正常退出,即在方法执行过程中遇到了异常,并且这个异常没有在方法中进行处理,即异常处理表中没有匹配的项,则方法会异常退出,将异常抛给上层方法进行处理。

(5)一些附加信息

《Java虚拟机规范》允许虚拟机实现增加一些规范里没有描述的信息到栈帧之中,例如与调试、 性能收集相关的信息,这部分信息完全取决于具体的虚拟机实现

2. 局部变量线程安全问题

m1()方法中sb是线程安全的,因为sb是方法内部的局部变量,且是每个线程的栈中私有的。而m2()和m3()方法中sb都是线程不安全的,变量sb有可能被其他线程修改。
因此看一个变量是否是线程安全的,不仅要看它是否为方法中的局部变量,还要看它是否会逃离方法的作用范围
在这里插入图片描述

3. 栈的内存溢出问题

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

  • 如果是固定大小的,当线程的栈中申请的内存超出限制时,会抛出一个StackOverflowError错误。例如在程序代码中没有正确的结束递归,导致递归方法栈帧无限压栈超出容量,就会抛出此异常。

  • 如果是可以动态扩展的,当线程无法向系统申请到足够的内存时,就会抛出OutofMemoryError错误

而广泛使用的Hotspot JVM不支持堆栈的动态扩展,栈的一般默认为512k-1024k(取决于操作系统),也可在jvm启动时通过-Xss size参数来指定。

参考:运行时内存篇——虚拟机栈

三、本地方法栈

Java虚拟机栈是用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用,逻辑结构和内存溢出情况都是一样的。

在JVM中有时需要和外界环境或者操作系统直接进行交互,需要调用其它语言(如C/C++)的函数方法,例如创建和使用线程,实际上是调用了操作系统提供的方法实现的。这样的方法称为本地方法,在Java中用native关键字修饰,在Java中并不提供具体的实现,而是运行时由jvm在本地方法库中进行调用。

实际上Hotspot JVM直接就将虚拟机栈和本地方法栈合二为一了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/127118.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决ubuntu(Linux)桌面/应用不插电掉帧问题

解决ubuntu(Linux)桌面/应用不插电掉帧问题 笔记本安装的ubuntu的gnome桌面,插电状态下触摸板动画丝滑,翻看浏览器文章的时候也不会有延迟掉帧的情况,但是离开了充电器,电池供电就会掉帧。 思路:在插电模式下&#x…

Spring Boot三种跨域解决方案与Spring Security跨域解决方案

跨域解决方案1、什么是跨域2、Spring Boot跨域解决方案1、服务端代码2、前端页面3、运行服务3、Spring Security跨域解决方案1、什么是跨域 什么是跨域,首先可以参考我之前写的这篇文章:JavaWeb跨域问题及解决方案 ,另外我下面会做补充。 很…

unreal中actor的property replicate简单小节

首先参考的网址是官网中的: https://docs.unrealengine.com/5.1/en-US/multiplayer-programming-quick-start-for-unreal-engine/ unreal引擎的版本是5.1 还原的过程相对比较简单,主要的精力花在了编译报错和调试的过程。 属性复制的流程如下&#xff…

尚医通-MongDB简介-安装-概念-操作(十六)

目录 (1)MongDB-简介和安装 (2)MongDB-概念和操作 (1)MongDB-简介和安装 1、NoSQL简介 MongDB为什么要用呢?之前我们用MySQL数据库,如果数据达到一定的量级,或者有高…

QT 之SQLite数据库

文章目录一、windows下使用命令行方法操作db文件1、 安装sqlite2、 使用sqlite二、QT操作sqlite1、 建立数据库2、 打开数据库3 、关闭数据库4、 创建数据表5 、插入数据6、 删除表数据7、 修改表数据8、 查询数据——遍历查询、条件查询一、windows下使用命令行方法操作db文件…

计算机网络期中考试部分题目

1. (1)以太网帧的数据部分是IP数据报,只要数出相应字段所在的字节即可。由图可知以太网帧头部有6+6214字节,IP数据报首部的目的P地址字段前有4x4 16字节,从帧的第1字节开始数141630字节,得目的P…

java怎么完成输出语句

我们在前面的文章和案例中,其实早就知道Java是如何实现输出功能的了。没错,就是利用System.out.println()语句来实现的!接下来壹哥就给大家详细解读一下这个语句的作用及其含义。 1. System 我们先来看看System是个什么东东。 System是Jav…

不推荐别的了,IDEA 自带的数据库工具就很牛逼!

MySQL 等数据库客户端软件市面上非常多了,别的栈长就不介绍了, 其实 IntelliJ IDEA 自带的数据库工具就很牛逼,不信你继续往下看。 本文以 IntelliJ IDEA/ Mac 版本作为演示,其他版本的应该也差距不大! 1、打开数据库…

JPE驱动器维修印刷机驱动器维修JV4-380-1410

印刷机水辘/墨辘/墨斗辊电机马达驱动器维修、墨控电机驱动器维修、JPE驱动器维修。 三菱印刷机电路板维修范围:东洋变频器维修,油墨电机维修,水辊变频器维修,电眼控制板维修,接口板维修,电源维修等。 小森…

【结构型】外观模式(Facade)

目录外观模式(Facade)适用场景外观模式实例代码(Java)外观模式(Facade) 为子系统中的一组接口提供一个一致的界面,外观模式 (Facade) 定义了一个高层接口,这个接口使得这一子系统更加容易使用。 适用场景 要为一个复杂子系统提…

【C++】初级面试整理

C基础 四种类型转换 static_cast:用于良性转换,一般不会导致意外发生,风险很低。常用于基本类型转换到 void,转换父类指针到子类不安全; const_cast:一般用于去掉const属性以及volatile,但是…

如何进行深度数据恢复?分享详细的恢复方法

有时我们会发现保存已久的照片,因为某些误操作导致它们消失了。通过多种方法都没有办法找回,这时该怎么办?不妨尝试下深度数据恢复的方法。它可以帮助我们找到更深层次的数据! 一、恢复数据前的一些问题 很多人都会遇到数据丢失的…

windows环境下安装RocketMQ

文章目录前言一、下载二、环境变量配置三、启动RocketMq1.启动nameserver2.启动broker四、RocketMq控制台安装1.下载2.修改配置文件3.打包4.启动前言 环境要求:JDK1.8Maven 3.2x;64为操作系统 一、下载 官网下载地址:https://rocketmq.apache.org/zh/…

xxljob 的路由策略如何理解,他的选择逻辑是什么(小白阅读)

目录 1 需求2 路由策略2.1 第一个 FIRST2.2 最后一个 LAST2.3 ROUND 轮询2.4 RANDOM :随机2.5 CONSISTENT_HASH:一致性HASH2.6 LEAST_FREQUENTLY_USED:最不经常使用2.7 LEAST_RECENTLY_USED :最近最久未使用2.8 FAILOVER :故障转移2.9 BUSYOVER :忙碌转移1 需求 xxljob …

Ansible变量定义和使用

剧本中使用变量 在playbook中,可以直接定义变量,如下所示: vars:变量名变量值,也可以写在下一级将改成冒号空格值的形式 debug:debug模块,msg消息 引用变量:使用两对{{ }} vim juben.yml - hosts: allvars:bianliang…

extern关键字以及加了头文件引用的作用

0.前言 xdm,今天是阳了的第一天,昨天是高烧,浑身酸痛,今天好多了。。。祝大家健康。 推荐一首歌《不是因为寂寞才想你》。看了《阿凡达2》,感觉没第一部好看哎。 1.extern 之前写过一篇博客extern关键字。今天讲一下和…

fpga实操训练(ip ram和ip fifo)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 所有的fpga ip当中,用的最多的ip一般有pll、rom、ram和fifo。前面,我们讨论过了rom,rom相比较ram和fifo而言&am…

弹性盒子(flex)

一、什么是弹性盒子 弹性盒子是一种用于按行或按列布局元素的一维布局方法。元素可以膨胀以填充额外的空间,收缩以适应更小的空间。 二、flex 模型说明 主轴(main axis): 是沿着 flex 元素放置的方向延伸的轴(比如页…

【vue】关于vuex的一点补充

1.vuex的基本和下载 1.vuex是一种集中管理模式,举个详细一点的例子就是公共的数据,函数和计算属性,允许任何组件来使用,修改这里面的数据,vuex也可以成为store处理模式,其中一个store示例有state&#xff…

hadoop大数据入门HDFS、MapReduce、YARN的个人通俗理解

大数据时代,在数据量,计算量,计算时间上都是单机无法胜任的,通过简单的增强单机已经无法解决。普遍的解决方案为将多个单机组合起来进行存储和计算的分布式集群来处理。 Hadoop支持使用普通机器组成可拓展的分布式主从集群实现了对大数据的分布式存储(HD…