JVM-虚拟机栈

虚拟机栈

Java虚拟机栈(Java Virtual Machine Stack采用栈的数据结构来管理方法调用中的基本数据,先进后出(First In Last Out),每一个方法的调用使用一个栈帧(Stack Frame)来保存。

接下来以这段代码为例

Java
public class MethodDemo {   public static void main(String[] args) {        study();    }public static void study(){eat();sleep();}   public static void eat(){       System.out.println("吃饭");   }    public static void sleep(){        System.out.println("睡觉");    }}

main方法执行时,会创建main方法的栈帧:

接下来执行study方法,会创建study方法的栈帧

 进入eat方法,创建eat方法的栈帧

eat方法执行完之后,会弹出它的栈帧: 

然后调用sleep方法,创建sleep方法栈帧

 最后study方法结束之后弹出栈帧,main方法结束之后弹出main的栈帧 

在IDEA中也可以看到对应的栈帧:

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("测试");}
}

打上断点debug之后会出现栈帧内容,由于上面的代码是方法调方法,我们也可以直观得看到,如果是递归调用太多次,就会造成很多栈帧存储到栈中,最终就会造成栈溢出 

 如果在C方法中发生了异常,虚拟机栈就会将此时的栈帧依次弹出栈,满足栈的先进后出,这也有一个Debug小技巧,出现异常时我们要定位问题,只需要找到最上面的方法即可

 Java虚拟机栈随着线程的创建而创建,而回收则会在线程的销毁时进行。由于方法可能会在不同线程中执行,每个线程都会包含一个自己的虚拟机栈。如下就有两个线程的虚拟机栈,main线程和线程A。

Java虚拟机栈的栈帧中主要包含三方面的内容

  • 局部变量表,局部变量表的作用是在运行过程中存放所有的局部变量
  • 操作数栈,操作数栈是栈帧中虚拟机在执行指令过程中用来存放临时数据的一块区域
  • 帧数据,帧数据主要包含动态链接、方法出口、异常表的引用

局部变量表

局部变量表的作用是在方法执行过程中存放所有的局部变量。局部变量表分为两种,一种是字节码文件中的,另外一种是栈帧中的也就是保存在内存中。栈帧中的局部变量表是根据字节码文件中的内容生成的。

字节码文件局部变量表

我们先来看下字节码文件中的局部变量表:编译成字节码文件时就可以确定局部变量表的内容。 

public static void test1(){int i = 0;long j = 1;
}

test1方法的局部变量表如下:

局部变量表中保存了字节码指令生效的偏移量: 

比如i这个变量,它的起始PC是2,代表从lconst_1这句指令开始才能使用i,长度为3,也就是2-4这三句指令都可以使用i。为什么从2才能使用,因为0和1这两句字节码指令还在处理int i = 0这句赋值语句。j这个变量只有等3指令执行完之后也就是long j = 1代码执行完之后才能使用,所以起始PC为4,只能在4这行字节码指令中使用。

 

栈帧局部变量表

栈帧中的局部变量表是一个数组,数组中每一个位置称之为槽(slot) ,long和double类型占用两个槽,其他类型占用一个槽。i占用数组下标为0的位置,j占用数组下标1-2的位置。 

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

方法参数也会保存在局部变量表中,其顺序与方法中参数定义的顺序一致。局部变量表保存的内容有:实例方法的this对象,方法的参数,方法体中声明的局部变量。 如下test3方法中包含两个参数k,m,这两个参数也会被加入到局部变量表中。 

槽数问题

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

为了节省空间,局部变量表中的槽是可以复用的,一旦某个局部变量不再生效,当前槽就可以再次被使用。

1、方法执行时,实例对象thiskm 会被放入局部变量表中,占用3个槽 

2、将1的值放入局部变量表下标为3的位置上,相当于给a进行赋值。 

3、将2放入局部变量表下标为4的位置,给b赋值为2。

 4、ab已经脱离了生效范围,所以下标为3和4的这两个位置可以复用。此时c的值1就可以放入下标为3的位置。

 5、最后放入j,j是一个long类型,占用两个槽。但是可以复用b所在的位置,所以占用4和5这两个位置

所以,局部变量表数值的长度为6。总而言之,JVM会在编译阶段就根据变量如果后续没有使用到的情况,就会将它所占用的槽释放(让其它变量能占用这个槽),从而减少数组占用的内存,这一点在编译期间就可以确定了,运行过程中只需要在栈帧中创建长度为6的数组即可。 

操作数栈 

操作数栈是栈帧中虚拟机在执行指令过程中用来存放中间数据的一块区域。他是一种栈式的数据结构,如果一条指令将一个值压入操作数栈,则后面的指令可以弹出并使用该值。

 在编译期就可以确定操作数栈的最大深度,从而在执行时正确的分配内存大小。

比如之前的相加案例中,操作数栈最大的深入会出现在这个时刻,由于两数相加,需要将两个数入到操作数栈进行相应的操作,栈的最大深入就是2 

 帧数据

帧数据主要包含动态链接、方法出口、异常表的引用。

动态链接 

当前类的字节码指令引用了其他类的属性或者方法时,需要将符号引用(编号)转换成对应的运行时常量池中的内存地址。动态链接就保存了编号到运行时常量池的内存地址的映射关系。

 

方法出口 

方法出口指的是方法在正确或者异常结束时,当前栈帧会被弹出,同时程序计数器应该指向上一个栈帧中的下一条指令的地址。所以在当前栈帧中,需要存储此方法出口的地址

异常表 

异常表存放的是代码中异常的处理信息,包含了异常捕获的生效范围以及异常发生后跳转到的字节码指令位置。

如下案例:i=1这行源代码编译成字节码指令之后,会包含偏移量2-4这三行指令。其中2-3是对i进行赋值1的操作,4的没有异常就跳转到10方法结束。如果出现异常的情况下,继续执行到7这行指令,7会将异常对象放入操作数栈中,这样在catch代码块中就可以使用异常对象了。接下来执行8-9,对i进行赋值为2的操作。所以异常表中,异常捕获的起始偏移量就是2,结束偏移量是4,在2-4执行过程中抛出了java.lang.Exception对象或者子类对象,就会将其捕获,然后跳转到偏移量为7的指令。

 

 栈内存溢出

Java虚拟机栈如果栈帧过多,占用内存超过栈内存可以分配的最大大小就会出现内存溢出。Java虚拟机栈内存溢出时会出现StackOverflowError的错误。

如果我们不指定栈的大小,JVM 将创建一个具有默认大小的栈。大小取决于操作系统和计算机的体系结构。 

要修改Java虚拟机栈的大小,可以使用虚拟机参数 -Xss 。

  • 语法:-Xss栈大小
  • 单位:字节(默认,必须是 1024 的倍数)、k或者K(KB)、m或者M(MB)、g或者G(GB)

 例如

Java
-Xss1048576
-Xss1024K     
-Xss1m
-Xss1g 

操作步骤如下,不同IDEA版本的设置方式会略有不同:

1、点击修改配置Modify options

2、点击Add VM options

3、添加参数

 

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

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

相关文章

vue3 之 通用组件统一注册全局

components/index.js // 把components中的所组件都进行全局化注册 // 通过插件的方式 import ImageView from ./ImageView/index.vue import Sku from ./XtxSku/index.vue export const componentPlugin {install (app) {// app.component(组件名字,组件配置对象)…

D7 Elasticsearch-Mongodb(搜索记录)

我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 知…

mysql笔记:表设计原则

mysql笔记:表设计原则 表对应了一个实体 表与表之间的关系: 一对一 一对多 多对多 一对一关系 例如:用户 user和身份信息 info 子表的外键关联了父表的子健(类型必须一样) 一对多关系 以电商系统为例子 用户-商…

CSP-202012-1-期末预测之安全指数

CSP-202012-1-期末预测之安全指数 题目很简单&#xff0c;直接上代码 #include <iostream> using namespace std; int main() {int n, sum 0;cin >> n;for (int i 0; i < n; i){int w, score;cin >> w >> score;sum w * score;}if (sum > 0…

使用 Ant Design 的 Upload 组件实现图片

文章目录 使用 Ant Design 的 Upload 组件实现图片Upload组件itemRender自定义上传列表项的渲染方式修改图片名上传图片上传链接中添加 Bearer Token 的请求头onPreview{handlePreview}上传成功后&#xff0c;如何隐藏上传列表 使用 Ant Design 的 Upload 组件实现图片 Upload…

【第二十三课】最小生成树:prime 和 kruskal 算法(acwing858,859 / c++代码 )

目录 前言 Prime算法--加点法 acwing-858 代码如下 一些解释 Kruskal算法--加边法 acwing-859 并查集与克鲁斯卡尔求最小生成树 代码如下 一些解释 前言 之前学最短路的时候&#xff0c;我们都是以有向图为基础的&#xff0c;当时我们提到如果是无向图&#xf…

【深度学习】实验7布置,图像超分辨

清华大学驭风计划 因为篇幅原因实验答案分开上传&#xff0c; 实验答案链接http://t.csdnimg.cn/P1yJF 如果需要更详细的实验报告或者代码可以私聊博主 有任何疑问或者问题&#xff0c;也欢迎私信博主&#xff0c;大家可以相互讨论交流哟~~ 深度学习训练营 案例 7 &#xff1…

计算机毕业设计Python+django医院后勤服务系统flask

结合目前流行的 B/S架构&#xff0c;将医疗后勤服务管理的各个方面都集中到数据库中&#xff0c;以便于用户的需要。该平台在确保平台稳定的前提下&#xff0c;能够实现多功能模块的设计和应用。该平台由管理员功能模块,工作人员模块&#xff0c;患者模块&#xff0c;患者家属模…

基于SpringBoot的记账系统项目

点击以下链接获取源码&#xff1a;https://download.csdn.net/download/qq_64505944/88822660?spm1001.2014.3001.5503 Java项目-8 开发工具&#xff1a;IDEA/Eclipse,MySQL,Tomcat 项目框架&#xff1a;SpringBoot,layui 功能&#xff1a;可以按照类型和时间查询&#xff0c…

基于tomcat运行jenkins常见的报错处理

目录 1.jenkins.util.SystemProperties$Listener错误 升级jdk11可能遇到的坑 2.java.lang.RuntimeException: Fontconfig head is null, check your fonts or fonts configuration 3.There were errors checking the update sites: UnknownHostException:updates.jenkins.i…

notepad++成功安装后默认显示英文怎么设置中文界面?

前几天使用电脑华为管家清理电脑后&#xff0c;发现一直使用的notepad软件变回了英文界面&#xff0c;跟刚成功安装的时候一样&#xff0c;那么应该怎么设置为中文界面呢&#xff1f;具体操作如下&#xff1a; 1、打开notepad软件&#xff0c;点击菜单栏“Settings – Prefere…

Modern C++ 内存篇1 - std::allocator VS pmr

大年三十所写&#xff0c;看到就点个赞吧&#xff01;祝读者们龙年大吉&#xff01;当然有问题欢迎评论指正。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. 前言 从今天起我们开始内存相关的话题&#xff0c;内存是个很大的话题&#xff0c;一时不…

探索未来:集成存储器计算(IMC)与深度神经网络(DNN)的机遇与挑战

开篇部分&#xff1a;人工智能、深度神经网络与内存计算的交汇 在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已经成为科技领域的一股强大力量&#xff0c;而深度神经网络&#xff08;DNN&#xff09;则是AI的核心引擎之一。DNN是一种模仿人类神经系统运作…

sqli.bypass靶场本地小皮环境(1-5关)

1、第一关 http://sqli.bypass/index1.php 单引号报错id1 双引号正常id1&#xff0c;应该是单引号闭合 id1--注释符用不了&#xff0c;%20和都用不了 %0a可以用 没有报错&#xff0c;用布尔盲注&#xff0c;POC&#xff1a;id1%0aand%0asubstr(ss,1,1)s%0aand%0a11 脚本跑数…

大模型学习笔记二:prompt工程

文章目录 一、经典AI女友Prompt二、prompt怎么做&#xff1f;1&#xff09;注重格式&#xff1a;2&#xff09;prompt经典构成3&#xff09;简单prompt的python询问代码4&#xff09;python实现订阅手机流量套餐的NLU5&#xff09;优化一&#xff1a;加入垂直领域推荐6&#xf…

GPT-4模型中的token和Tokenization概念介绍

Token从字面意思上看是游戏代币&#xff0c;用在深度学习中的自然语言处理领域中时&#xff0c;代表着输入文字序列的“代币化”。那么海量语料中的文字序列&#xff0c;就可以转化为海量的代币&#xff0c;用来训练我们的模型。这样我们就能够理解“用于GPT-4训练的token数量大…

从一到无穷大 #23 《流计算系统图解》书评

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言内容总结 引言 春节假期回到家里断然是不会有看纸质书的时间的。造化弄人&#…

HCIA--ACL和远程登陆实验

1.划分网段&#xff0c;配IP地址&#xff0c;启用OSPF协议&#xff1a; AR1配置&#xff1a; [Huawei]sys R1 [R1]int g0/0/0 [R1-GigabitEthernet0/0/0]ip add 192.168.1.1 24 [R1-GigabitEthernet0/0/0]int g0/0/1 [R1-GigabitEthernet0/0/1]ip add 12.1.1.1 24 [R1-Gigabi…

STM32的ADC电压采集

时间记录&#xff1a;2024/2/9 一、ADC相关知识点 &#xff08;1&#xff09;STM32的ADC时钟不要超过14MHz&#xff0c;不然结果的准确率将下降 &#xff08;2&#xff09;ADC分为规则组和注入组&#xff0c;规则组相当于正常运行的程序&#xff0c;注入组相当于中断可以打断…

贵金属交易包括哪些?香港有哪些贵金属交易平台?

随着金融市场的不断发展&#xff0c;贵金属交易作为一种投资方式&#xff0c;越来越受到投资者的关注。贵金属交易不仅具有投资价值&#xff0c;还能够为投资者提供规避风险和保值的工具。本文将介绍贵金属交易的种类和香港的贵金属交易平台。 一、贵金属交易的种类 贵金属交…