当前位置: 首页 > news >正文

Java虚拟机 -虚拟机栈

虚拟机栈详解

  • 虚拟机栈
    • 概述
      • 案例
      • 常见的跟虚拟栈异常相关的异常
        • StackOverflowError异常
        • OutOfMemoryError异常
    • 栈的基本存储单位
    • 局部变量表
      • IDEA Jclasslib Bytecode Viewer插件
      • slot
    • 操作数栈
    • 方法调用(待后续补充)

虚拟机栈

上一篇文章,我们简单介绍了一下虚拟机栈,虚拟机栈涉及的内容很多,所以我们另外再专门开一篇文章来讲述一下虚拟机栈。我们在写代码的过程中,经常会遇见Java程序异常的时候,通常这个时候我们的程序会打印出一系列堆栈信息。而我们通过这些堆栈信息就可以很清楚的知道我们的方法的调用链路,进而排查问题。堆栈是由栈帧组成,而栈帧里面又包含局部变量表 操作数栈 动态链接 方法返回地址等信息组成。下面我们将对这些内容进行详细介绍,希望通过我的介绍能让大家对虚拟机栈有一个比较深入的理解。

概述

Java语言由于跨平台性,所以指令集是以栈为基础设计的。每个线程创建的时候都会创建一个虚拟机栈,内部每一个栈都是由一系列栈帧组成,每一个栈帧又对应了一个方法调用。虚拟机栈跟数据结构中的栈有类似的特点,都是先进后出,只支持入栈与出栈两种操作。另外栈是线程私有的。

案例

public class StackTest {public void test1() {int a = 0;int b = 0;test2();}public void test2() {int a = 0;int b = 0;test3();}public void test3() {int a = 0;int b = 0;}public static void main(String[] args) {StackTest stackTest = new StackTest();stackTest.test1();}
}

在这里插入图片描述
虚拟机栈保存方法的局部变量1和方法调用返回结果。虚拟机栈不存在垃圾回收问题,但是存在内存溢出问题,栈先进后出,每个新的放啊执行的时候都要伴随着压栈操作;方法执行结束后,伴随着出栈操作。

常见的跟虚拟栈异常相关的异常

虚拟机栈内存溢出问题常见的异常有两种:

  1. 如果是固定大小的虚拟机栈,虚拟机栈的大小固定,因为每一个新方法的调用都伴随着压栈操作,当新方法足够多的时候就可能把固定大小虚拟机栈内存用完,这个时候就会爆出StackOverflowError异常
  2. 如果虚拟机栈大小可以动态变化,但是尝试获取新的内存空间的时候,没有内存资源的时候,JVM就会抛出OutOfMemoryError异常
StackOverflowError异常

代码案例:

public class StackOverflowError {public static int counter = 0;public void setCounter() {counter++;setCounter();}public static void main(String[] args) {StackOverflowError stackOverflowError = new StackOverflowError();try {stackOverflowError.setCounter();} catch (Throwable e) {System.out.println("调用深度:" + counter);e.printStackTrace();}}
}

我们可以通过设置-Xss参数来设置线程的最大虚拟机栈的大小,栈的大小会直接影响调用栈的深度。

在这里插入图片描述

  1. Xss设置为256k的时候
    在这里插入图片描述

  2. Xss设置为512K的时候
    在这里插入图片描述
    可以明显看到,我们的虚拟机栈的大小扩大之后,调用栈的深度也随之扩大。

OutOfMemoryError异常

代码案例:

public class OutOfMemoryError {public static void main(String[] args) {int i = 0;while (true) {Thread thread = new MyThread();thread.start();}}
}class MyThread extends Thread {CountDownLatch startSignal = new CountDownLatch(1);public void run() {while (true) {try {startSignal.await();}catch (InterruptedException e) {e.printStackTrace();}}}
}

栈的基本存储单位

每个线程都有自己的栈,栈中的数据都是以栈帧的形式存在。这个线程上执行的每个方法都各自对应一个栈帧2。在一个运行状态的线程中,一个时间点上只会有一个活动的栈帧即栈顶栈帧在活动。之前说过的,每一个栈帧都对应的一个方法,如果当前方法执行新的方法,那又会有新的栈帧被创建出来,放在栈顶成为新的栈帧。

局部变量表

局部变量表定义为一个数字数组,主要用于存储方法参数和定义在方法体内部的局部变量,数据类型包括基本数据类型、引用数据类型以及returnAddress类型。基本数据类型直接存储的是其值;引用数据类型存储的是对对象的引用。
局部变量是属于栈帧,而栈帧又属于虚拟机栈,因而局部变量是线程私有的,不存在并发的数据安全问题。

局部变量表所需要的容量大小是编译期就确定的,保存在方法的code属性的maximum local variables数据项中。局部变量是按照运行期间所需要的最大大小确定的,运行期间不会改变它的大小。

IDEA Jclasslib Bytecode Viewer插件

通过IntelliJ IDEA安装Jclasslib Bytecode Viewer插件可以查看局部变量表。安装好插件以后,单击“View”选项,选择“Show Bytecode With Jclasslib”选项
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

slot

局部变量的基本存储单位是slot(变量槽)。在局部变量表里面,32位以内的基本类型占用一个slot,64位的类型占用两个slot。byte、short、char在存储前被转换为int,boolean也被转换为int,0表示false,非0表示true。long和double则占据两个slot。JVM会为局部变量表中的每一个slot都分配一个访问索引,通过这个索引即可成功访问到局部变量表中指定的局部变量值。
当一个实例方法被调用的时候,它的方法参数与方法体内部的定义的局部变量将会按照顺序被复制到局部变量中的每一个slot上去。如果方法是实例方法,slot 0 处放的是this指针。
另外局部变量中的slot可以重用,局部变量过了作用域之后,后面的新的局部变量可以占用它的位置。

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

操作数栈

栈帧除了包含局部变量之后,还包含一个操作数栈。它主要用于保存计算过程的中间结果,同时作为计算过程中变量的临时存储空间。因为它也是栈结构,所以只又进栈与出栈两种操作。每一个操作数栈的深度在编译器就确定了,保存在Maximum stack size数据中。我们之前说JVM是基于栈的,这个栈指的就是操作数栈。

方法调用(待后续补充)


  1. 8种基本数据类型以及对象的引用类型 ↩︎

  2. 栈帧是一个内存区块,是一个数据集,里面维持着方法执行过程中的各种数据信息。
    在这里插入图片描述
    在这里插入图片描述 ↩︎

http://www.xdnf.cn/news/567991.html

相关文章:

  • 名师在线杂志名师在线杂志社名师在线编辑部栏目设置
  • 制作一款打飞机游戏53:子弹样式
  • 【Qt】:设置hover属性,没有适应到子控件中
  • 工业相机图像采集卡:机器视觉的核心枢纽
  • 04算法学习_209.长度最小的子数组
  • OS进程调度
  • 第23天-Python Flet 开发指南
  • 多模态大语言模型arxiv论文略读(八十六)
  • LAN(局域网)和WAN(广域网)
  • 深入理解万维网:URL、HTTP与HTML
  • 电路设计基础
  • 前端JavaScript-嵌套事件
  • matlab加权核范数最小化图像去噪
  • Linux——PostgreSQL数据库日常维护
  • 25_05_19Linux实战篇、第一章_02若依前后端部署之路(前端)
  • 在 Excel xll 自动注册操作 中使用东方仙盟软件————仙盟创梦IDE
  • 代码随想录 算法训练 Day8:字符串part01
  • 关于TCP三次握手
  • 【ULR #1】打击复读 (SAM, DAG链剖分)
  • PHP学习笔记(八)
  • Linux操作系统之进程(二):进程状态
  • cocos creator使用jenkins打包微信小游戏,自动上传资源到cdn,windows版运行jenkins
  • 攻防世界-stegano
  • 物流项目第五期(运费计算实现、责任链设计模式运用)
  • TDengine 运维—容量规划
  • 学习 Android(十一)Service
  • 安卓蓝牙frameworks/base/core/java/android/bluetooth这个路径下文件的作用
  • Android 自定义SnackBar和下滑取消
  • 命令行参数和环境变量
  • 力扣热题100,力扣148.排序链表力扣.26找出字符串中第一个匹配项的下标力扣146.LRU缓存序列管理器