【基础篇】九、程序计数器 JVM栈

文章目录

  • 0、运行时数据区域
  • 1、程序计数器
  • 2、JVM栈
  • 3、JVM栈--栈帧--局部变量表
  • 4、JVM栈--栈帧--操作数栈
  • 5、JVM栈--栈帧--桢数据
  • 6、栈溢出
  • 7、设置栈空间大小
  • 8、本地方法栈

0、运行时数据区域

在这里插入图片描述

JVM结构里,类加载器下来,到了运行时数据区域,即Java程序运行时,JVM管理的内存区域,其又分为:

在这里插入图片描述

栈这里可以细划分为两部分:

  • Java虚拟机栈:保存在Java中的方法
  • 本地方法栈:保存的native方法,c++实现的那些

1、程序计数器

程序计数器(Program Counter Register)也叫PC寄存器,每个线程会通过它来记录接下来要执行的的字节码指令的地址

在这里插入图片描述

举个例子:

在这里插入图片描述

类加载阶段,类加载器将字节码指令读到内存中后,将原来的偏移量改为内存地址,每条字节码指令都对应一个内存地址

在这里插入图片描述

执行完当前这一条指令后,JVM的执行引擎(JIT、解释器等)根据程序计数器中记录的数据,就拿到了接下来要执行的指令的地址。

在这里插入图片描述

多线程下,CPU从线程A切换到线程B,得知道线程B之前解释执行到哪一句指令了,此时JVM的程序计数器就发挥作用了

在这里插入图片描述

2、JVM栈

JVM的栈采用栈的数据结构,保存方法调用的基本数据,先进后出,其中,每一个调用的方法用一个叫栈帧的东西存。

如下图,流程为:

main入栈
study入栈
eat入栈
eat出栈.....
sleep入栈
sleep出栈.....
study出栈.....
main出栈.....
执行结束!

在这里插入图片描述

断点打在C方法里,看下IDEA中debug的栈信息,点击栈里的每个方法,跳到当前该方法执行在的那一行:

在这里插入图片描述

修改程序,让C程序抛出异常:

public class FrameDemo{public static void main(String[] args){A();}public static void A(){System.out.println("A执行了...");B();}public static void B(){System.out.println("B执行了...");C();}public static void C(){System.out.println("C执行了...");throw new RuntimeException("测试");   //异常}
}

可以发现,结果里也展示了异常发生时的栈信息,以及每个方法具体执行到哪一行了:

在这里插入图片描述

JVM的栈随着线程的创建而创建,也随着线程的销毁而回收,每个线程都有一个自己的JVM栈

在这里插入图片描述

3、JVM栈–栈帧–局部变量表

栈里的一个个栈帧,由三部分构成:

在这里插入图片描述

局部变量表用来存方法执行过程中的所有局部变量,类被编译成字节码时,局部变量表的内容就确定了:

在这里插入图片描述

想访问一个变量,自然是要在它声明定义之后,所以局部变量表里的起始PC就是保存了从哪一行字节码指令开始,可以访问这个变量,对于变量i,其值就为2。而长度字段为3,即代表在2.3.4这三行里可以访问i。总之就是通过局部变量表控制可以访问每个变量的范围。 是字节码文件中的局部变量表,它的作用是做安全性上的校验,比如变量的生效范围。

在这里插入图片描述

而栈帧自己的局部变量表就是一个数组,数组的每个位置叫槽slot,long和double类型占用两个槽,其他类型占用一个槽。 如上图,i占0号位,一个槽,后面long类型的j则占两个。再看字节码文件里局部变量表中的序号,其实就是这个局部变量i,在栈帧的局部变量表的起始槽的编号。

在这里插入图片描述

实例方法中的序号为0的位置存放的是this,指的是当前调用方法的对象,运行时会在内存中存放实例对象
的地址。

在这里插入图片描述

局部变量表也会存方法的形参,且顺序与形参顺序一致。

一句话,局部变量表中存的是实例方法的this对象、方法的形参、方法体中声明的局部变量

注意,局部变量表的槽可以重复使用,一旦某个局部变量不再生效,当前槽就可以再次被使用

public void test4(int k,int m){{int a = 1;int b = 2;}{int c = 1;}int i = 0;long j = 1;
}

执行完b=2时,栈帧的局部变量表长这样:

在这里插入图片描述

再往下走,字节码为:

iconst_1
istore_3

即把字面量1放入了3号槽,复用了a变量的槽。同理往下推,最终的局部变量表长这样:

在这里插入图片描述

因此,上面的代码在其栈帧的局部变量表中会占用6个槽,而不是简单的1+1+1 +1+1 +1 +1+2 = 9

4、JVM栈–栈帧–操作数栈

  • 操作数栈是JVM在执行指令时,用来存放中间数据的区域
  • 栈的数据结构,压栈+弹栈
  • 编译器就可决定操作数栈的最大深度,用jclasslib验证:
    在这里插入图片描述

分析下以上源码的字节码:

在这里插入图片描述

操作数栈的变化过程如下:

在这里插入图片描述
在这里插入图片描述

最终状态:
在这里插入图片描述

可以看到,整个过程中,操作数栈里最多有两个数据,即操作数栈的最大深度为2,此时创建栈帧时,创建深度为2的操作数栈即可。

5、JVM栈–栈帧–桢数据

桢数据主要含:

  • 动态链接
  • 方法出口
  • 异常表引用
Part1:动态链接

在这里插入图片描述
当前类的字节码中引用了别的类的方法或属性,要将符号引用(#10)转成内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。

Part2:方法出口

在栈帧的桢数据中,存放了上一个方法的地址(sleep方法的桢数据有study方法执行到哪一行的信息)
在这里插入图片描述

当方法正常结束或发生异常结束时,当前栈帧被弹出,同时程序计数器指向上一个栈帧的下一条指令地址:

在这里插入图片描述

Part3:异常表引用

存放异常捕获的范围,以及这个范围发生异常后跳哪一行。 eg:看异常表的第一行,从起始PC 0到结束PC 2,如果发生异常,就跳转到第7行,astore_0即把捕获的异常对象e放到局部变量表中,因为catch块中大概率会用到e对象

在这里插入图片描述

6、栈溢出

一个线程的栈里,栈帧过多,占用的内存到达了分配的最大值,再入栈就会StackOverflowError,即栈溢出。

在这里插入图片描述

如下为OpenJDK8里JVM的源码,不指定栈的大小时,JVM创建的是一个默认大小的栈,不同的操作系统里,这个默认值也不同。

在这里插入图片描述

用无停止条件的递归来看栈溢出:

public static int count = 0;
//递归方法调用自己public static void recursion(){System.out.println(++count);recursion();}

在这里插入图片描述
运行,默认情况下,main线程的栈里放了大约10473个栈帧:

在这里插入图片描述

7、设置栈空间大小

添加JVM参数:

-Xss栈大小

单位默认是byte字节(默认,必须是 1024 的倍数),可选k或者K(KB)、m或者M(MB)、g或者G(GB)

eg:
-Xss1048576 
-Xss1024K 
-Xss1m
-Xss1g

在这里插入图片描述
设置线程栈空间大小,还可以用另一个参数:

//注意等号-XX:ThreadStackSize=1024

HotSpot对栈空间的大小有范围限制,Windows(64位)下的JDK8测试最小值为180k,最大值为1024m,超过这个范围,即使设置了也不会生效。

//无效
-Xss1k
-Xss1025m

当然,局部变量过多(栈帧局部变量表大)、操作数栈深度大,在相同大小下,能存的栈帧数量也就少了。最后,工作中,该值建议用

-Xss256k

8、本地方法栈

JVM栈中存的是Java方法的栈桢,本地方法栈里存的则是native本地方法的栈帧。不过在HotSpot虚拟机中,JVM栈和本地方法栈实现上使用了同一个栈空间。

在这里插入图片描述

如下:

在这里插入图片描述

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

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

相关文章

视图与索引连表查询(内/外联)和子查询

目录 一、视图 1.1、概念: 1.2、场景: 1.3、用视图的意义 1.2、创建(增加)视图 1.3、修改视图 1.4、删除视图 1.5、查看视图 ​编辑 二、索引 2.1、概念 2.2、优缺点 优点: 缺点: 2.3、应用场景 2.4、会失效 2.5、…

JavaWeb——新闻管理系统(Jsp+Servlet)之jsp新闻查询

java-ee项目结构设计 1.dao:对数据库的访问,实现了增删改查 2.entity:定义了新闻、评论、用户三个实体,并设置对应实体的属性 3.filter:过滤器,设置字符编码都为utf8,防止乱码出现 4.service:业务逻辑处理 5.servlet:处…

【WPF】使用 WriteableBitmap 提升 Image 性能

【WPF】使用 WriteableBitmap 提升 Image 性能 前言WriteableBitmap 背景WriteableBitmap 渲染原理WriteableBitmap 使用技巧案例核心源码测试结果 前言 由于中所周不知的原因,WPF 中想要快速的更新图像的显示速率一直以来都是一大难题。在本文中,我将分…

Android学习(一):Android Studio安装与配置

Android学习(一):Android Studio安装与配置 一、安装 下载地址 下载zip文件,免安装。 二、下载资源 启动后,出现该弹框,点击Cancel。 点击Next 默认,点击Next。 点击Next。 点击Finish 开始…

性能优化-OpenMP基础教程(二)

本文主要介绍OpenMP并行编程技术,编程模型、指令和函数的介绍、以及OpenMP实战的几个例子。希望给OpenMP并行编程者提供指导。 🎬个人简介:一个全栈工程师的升级之路! 📋个人专栏:高性能(HPC&am…

学习Redis缓存

学习Redis缓存 NoSQL和SQL的区别缓存缓存作用缓存成本添加Redis缓存 Redis特征Redis中数据结构Redis通用命令String类型Key的层级格式Hash类型Redis的Java客户端 NoSQL和SQL的区别 缓存 缓存就是数据交换的缓冲区,是存储数据的临时地方,一般读写性比较高…

async和await关键字

目录 async 关键字await 关键字使用 async 和 await 解决回调地狱问题错误处理总结 在JavaScript中, async和 await是用于简化基于 Promise的异步编程的关键字。在ES2017(也称为ES8)中引入后,它们迅速成为管理异步代码的首选方…

SQL高级:事务

在前面的内容中,我们学习了很多SQL的高级语法,包括窗口函数,存储过程等。在这篇文章中,我们要学习一个很重要的概念,事务。 事务的定义 为了讲清楚事务,很多人拿银行转账来举例,不得不说这真的是一个非常恰当的例子。一个账户要增加对应的金额,另一个账户需要减少对应…

RT-DETR Gradio 前端展示页面

效果展示 使用方法 Gradio 是一个开源库,旨在为机器学习模型提供快速且易于使用的网页界面。它允许开发者和研究人员轻松地为他们的模型创建交互式的演示,使得无论技术背景如何的人都可以方便地试用和理解这些模型。使用Gradio,你只需几行代码就可以生成一个网页应用程序,…

【C程序设计】C函数指针与回调函数

函数指针 函数指针是指向函数的指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 函数指针可以像一般函数一样,用于调用函数、传递参数。 函数指针变量的声明: typedef int (*fun_ptr)(int,i…

mysql之视图mysql连接案例索引

文章目录 一、视图1.1 含义1.2 操作1.2.1 创建视图1.2.2 视图的修改1.2.3 删除视图1.2.4 查看视图 二、连接案例01)查询" 01 "课程比" 02 "课程成绩高的学生的信息及课程分数02)查询同时存在" 01 "课程和" 02 "课程的情况03&#xff0…

【信息论与编码】习题-判断题-第二部分

目录 判断题 第二部分24. 信道矩阵 代表的信道的信道容量C125. 信源熵具有严格的下凸性。26. 率失真函数对允许的平均失真度具有上凸性。27. 信道编码定理是一个理想编码的存在性定理,即:信道无失真传递信息的条件是信息率小于信道容量 。28. 信道的输出…

修改 Ubuntu 的配置

目录 一、修改地址 1. 修改本机IP 二、修改网关 1. 查看网关地址 2. 设置默认网关 三、重启网络 1. 重启网络 2. 刷新网络 四、修改主机名 1. 查看主机名 2. 修改主机名 一、修改地址 1. 修改本机IP sudo ifconfig en…

【视频图像篇】模糊图像增强技术之视频平均帧处理

【视频图像篇】模糊图像增强技术之视频平均帧处理 0、目录 1、实验环境 2、集成和超级分辨率 3、色彩清晰化 4、翻转 总结 1、实验环境 系统环境Windows 11 专业版,[23H2(22631.2715)Impress,[v8.0.3.2] 2、集成和超级分辨…

如何使用VsCode编译C语言?

下载VsCode (1) 解压到D盘跟目录 (2) 运行[vscode.reg],注册右键菜单 (3) 进入[pack]文件夹,运行[install.bat]。安装基本插件。 下载mingw32 (1) 解压任意目录 (2) 我的电脑右键–高级系统设置–高级–环境变量–系统变量–Path(双击)–空白行(双击)–…

MySQL之视图索引执行计划

目录 一.视图 二.执行计划 2.1.什么是执行计划 2.2.执行计划的作用 三.使用外连接、内连接和子查询进行举例 四.思维导图 好啦今天就到这里了哦!!!希望能帮到你哦!!! 一.视图 含义 :在数…

二手买卖、废品回收小程序 在app.json中声明permission scope.userLocation字段 教程说明

处理二手买卖、废品回收小程序 在app.json中声明permission scope.userLocation字段 教程说明 sitemapLocation 指明 sitemap.json 的位置;默认为 ‘sitemap.json’ 即在 app.json 同级目录下名字的 sitemap.json 文件 找到app.json这个文件 把这段代码加进去&…

@Transactional 注解的12种失效场景

请直接看原文: 原文链接:啪!啪!Transactional 注解的12种失效场景,这坑我踩个遍-腾讯云开发者社区-腾讯云 (tencent.com) ------------------------------------------------------------------------------------------------------------…

Kafka(四)Broker

目录 1 配置Broker1.1 Broker的配置broker.id0listererszookeeper.connectlog.dirslog.dir/tmp/kafka-logsnum.recovery.threads.per.data.dir1auto.create.topics.enabletrueauto.leader.rebalance.enabletrue, leader.imbalance.check.interval.seconds300, leader.imbalance…