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、方法执行时,实例对象this、k、m 会被放入局部变量表中,占用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、添加参数
相关文章:

JVM-虚拟机栈
虚拟机栈 Java虚拟机栈(Java Virtual Machine Stack)采用栈的数据结构来管理方法调用中的基本数据,先进后出(First In Last Out),每一个方法的调用使用一个栈帧(Stack Frame)来保存。 接下来以…...
linux系统上tomcat简介以及安装tomcat
tomcat简介以及安装 Tomcat简介安装环境安装jdk安装tomcat浏览器访问 Tomcat简介 Tomcat是一个开源的Web服务器和servlet容器,由Apache软件基金会开发和维护。它是一种流行的Java Web应用服务器,用于运行Java编写的Web应用程序。 Tomcat提供了一个轻量级…...

树莓派的pip安装时候添加清华源
每次都要去找镜像网址,太麻烦了,通过改配置可以一次性解决。 首先创建一个.pip 目录 mkdir ~/.pip意味着在当前目录下创建.pip文件,不过这个是隐藏文件,一般情况下是关闭隐藏文件的可视的,于是我绕了点弯弯。 编辑…...

共享网盘系统PHP源码
新V5.0版本,支持上传视频、支持视频播放、支持共享,也可以自己用。 可以自动生成视频外链,下载地址,播放器代码,html代码,ubb代码等等。 使用方法: 源码上传到服务器,打开网站根据…...

unity-ios-解决内购商品在Appstore上面已配置,但在手机测试时却无法显示的问题
自己这几天用 unity 2021 xcode 14.2 开发ios内购,appstore上面内购商品都已经配置好了,但是在手机里就是不显示,最后才发现必需得满足以下条件才行: 1. Appstore后台 -> 内购商品 -> 商品状态必需为『准备提交』以上状态…...
flask的基本使用 token插件(二)
一、安装flask-jwt-extended 安装flask-jwt-extend得时候 会自动安装一个pyjwt得库。pyjwt可以直接使用来生成JWT和验证。但是在flask中,可以通过Flask-JWT-Extended来实现JWT能,因为他封装了使用方式,以及一些属性和装饰器,用起…...

云计算、Docker、K8S问题
1 云计算 云计算作为一种新兴技术,已经在现代社会中得到了广泛应用。它以其高效、灵活和可扩展特性,成为了许多企业和组织在数据处理和存储方面的首选方案。 1.1 什么是云计算?它有哪些特点? 云计算是一种通过网络提供计算资源…...

【Iceberg学习二】Branch和Tag在Iceberg中的应用
Iceberg 表元数据保持一个快照日志,记录了对表所做的更改。快照在 Iceberg 中至关重要,因为它们是读者隔离和时间旅行查询的基础。为了控制元数据大小和存储成本,Iceberg 提供了快照生命周期管理程序,如 expire_snapshots…...
在 Blazor WASM 中手撸一个.NET MD5类
最近.net8 blazor auto大火, 我也玩了一下,发现ssr能用的代码 MD5 类在wasm是没法用的. 于是搜索了一下互联网,找到了一份代码,分享给大家. 我找到的帖子作者原话: 代码不是我的,但我确实稍微修改了它以使其与 System.Security.Cryptography.MD5 类更加一致。 pub…...

MFC实现遍历系统进程
今天我们来枚举系统中的进程和结束系统中进程。 认识几个API 1)CreateToolhelp32Snapshot 用于创建系统快照 HANDLE WINAPI CreateToolhelp32Snapshot( __in DWORD dwFlags, //指定快照中包含的系统内容__in DWORD th32P…...

【C语言】深入理解指针
目录 1.字符指针 2.指针数组 3.数组指针 4.数组传参与指针传参 一维数组传参 二维数组传参 一级指针传参 二级指针传参 5.函数指针 6.函数指针数组 7.指向函数指针数组的指针(了解即可) 8.回调函数 回调函数的应用:库函数qsort …...

Excel——有效性、二级菜单联动
一、录入规范数据 1.手动输入序列录入有效性信息 选择需要录入有效性的所有单元格 选择【数据】——【有效性】——【有效性】 在【允许】输入的值之间选择【序列】 在【序列】输入框中输入想要选择的值,中间用逗号(必须是英文逗号)隔开 。…...
计算机网络总结
1. 网络分层 网络上进行协议分层的好处 ①分层之后层次之间的耦合程度比较低,上层协议不必了解下层的细节,下层也不必了解上层的细节; ②方便的对某一层的协议进行替换; 真实网络的协议分层 OSI 七层网络模型(教科书&…...

初识文件包含漏洞
目录 什么是文件包含漏洞? 文件包含的环境要求 常见的文件包含函数 PHP伪协议 file://协议 php://协议 php://filter php://input zip://、bzip2://、zlib://协议 zip:// bzip2:// zlib:// data://协议 文件包含漏洞演示 案例1:php://inp…...

AR特效自研AI算法技术解决方案
在当今这个高速发展的数字化时代,增强现实(AR)技术已经成为企业创新和市场竞争的重要手段。美摄科技凭借对AI技术的深厚积累,为企业提供了一套创新的AR特效自研AI算法技术解决方案,旨在满足企业在AR领域的多元化需求。…...
牛客2024年除夕娱乐赛(题解)
比赛地址 : 牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A 看题面然后猜!!! #include<bits/stdc.h> using namespace std; int main(){cout << "原神启动" << endl; } B 也是看题面然后猜 : #include<bits/stdc.…...
5 scala的函数式编程简介
与Java一样,Scala 也是使用 Lambda 表达式实现函数式变成的。 1 遍历 除了使用 for 可以对数组、List、Set 进行遍历外,也可以使用 foreach 函数式编程进行遍历,使代码更为简洁。 foreach 的方法签名为: foreach(f: (A) > …...

陪护系统|陪护小程序提升长者护理服务质量的关键
在如今逐渐老龄化的社会中,老年人对更好的护理服务需求不断增加。科技的进步使得陪护小程序系统源码成为提供优质服务的重要途径之一。本文将从运营角度探讨如何优化陪护小程序系统源码,提升长者护理服务的质量。 首先,我们需要对软件的设计和…...

C++算法之双指针、BFS和图论
一、双指针 1.AcWing 1238.日志统计 分析思路 前一区间和后一区间有大部分是存在重复的 我们要做的就是利用这部分 来缩短我们查询的时间 并且在使用双指针时要注意对所有的博客记录按时间从小到大先排好顺序 因为在有序的区间内才能使用双指针记录两个区间相差 相当于把一个…...
【大厂AI课学习笔记】1.5 AI技术领域(3)自然语言处理
今天来梳理自然语言处理的相关内容。 自然语言处理:定义、关键技术、技术发展、应用场景与商业化成功 一、自然语言处理的定义 自然语言处理(NLP)是人工智能(AI)领域的一个重要分支,它研究的是如何让计算…...

华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...

STM32标准库-DMA直接存储器存取
文章目录 一、DMA1.1简介1.2存储器映像1.3DMA框图1.4DMA基本结构1.5DMA请求1.6数据宽度与对齐1.7数据转运DMA1.8ADC扫描模式DMA 二、数据转运DMA2.1接线图2.2代码2.3相关API 一、DMA 1.1简介 DMA(Direct Memory Access)直接存储器存取 DMA可以提供外设…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...