前言

虚拟机栈也称为Java栈,每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧(Stack Frame)

栈特点基本介绍

  1. Java虚拟机栈属于线程私有,它的生命周期与线程相同(随线程而生,随线程而灭)
  2. 虚拟机栈说明了线程运行时的瞬时状态
  3. 每次方法调用,都会产生对应的栈帧
  4. 栈帧包括局部变量表、操作数栈、动态链接、方法返回地址和一些附加信息
  5. 每个方法被调用至执行完毕的过程,就对应这个栈帧在虚拟机栈中从入栈到出栈的完整过程
  6. 栈的深度有限制


局部变量表

  • 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量,并在Java编译为Class文件时,就已确定该方法所需分配的局部变量表的最大容量
  • 局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)
  • 线程私有,不允许跨线程访问,随方法调用创建,方法退出销毁
  • 编译期间长度已经确定,局部变量元数据存储在字节码中
  • 局部变量表是栈帧最主要的存储空间,决定了栈的深度

操作数栈

保存中间计算的临时结果,字节码指令在执行过程中的中间计算结果存储在操作数栈

  • 操作数栈(Operand Stack)也常被成为操作栈,是一个后入先出栈,用于保存计算过程中的中间结果,同时作为计算过程中变量临时的存储空间。其最大深度在编译时就被写到了Code属性的max_stacks中
  • 操作数栈在方法的执行过程中,根据字节码指令往栈中写入数据或提取数据,即入栈和出栈操作。虽然栈是用数组实现的,但根据栈的特性,对栈中数据访问不能通过索引,而是只能通过标准的入栈和出栈操作来完成一次数据访问

动态连接

将符号引用转为直接引用

  • 每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用
  • 持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)
  • 在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析
  • 另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接

方法出口

存放调用方法的程序计数器

当一个方法开始执行后,有2种方式可以退出这个方法

  • 方法返回指令 : 执行引擎遇到一个方法返回的字节码指令(return),这时候可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口
  • 异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出
  • 一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中会保存这个计数器值,而方法异常退出时,返回地址要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息

假如有下面这样一段代码,在一个main方法中调用了method1,再在method1调用method2

案例演示

public class MyMethod {public static void main(String[] args) {new MyMethod().method1();}public void method1(){System.out.println("进入method1 ...");int a=1;int b=2;method2();System.out.println("退出method1");}public void method2(){System.out.println("进入method2 ...");int c=3;int d=4;System.out.println("退出method2");}}

对应一个简单的栈帧图示可表示如下:

在数据结构中,栈属于一种典型的先进后出的数据结构,即先被压入栈的数据最后出来,对应到上面的案例中,Method2最后入栈,因此当Method2方法执行完毕后,最先从栈弹出,直到Main方法完成,当前这个线程的虚拟机栈就销毁,这也符合预期的方法调用返回结果

在idea中通过安装jclasslib插件,可以清楚的看到方法的字节码运行过程中的详细信息,如下,我们分析method2这个方法在调用时的栈帧过程时候,通过显示的字节码信息可以看出来该方法中的局部变量信息,结果返回时机等


栈空间设置

  • Java1.5之后默认每个栈空间大小为1MB
  • Java启动参数: -Xss 数值【k|m|g】
  • 栈内存分配决定了栈的最大深度,栈内存的深度在实际中是动态的,会随着每个栈中调用方法的数量不同而不同,在某些极端情况下,比如栈的空间不够了或者打满了,就会抱出栈溢出的错误,即OutOfMemoryError异常;

栈的两种常用空间配置:

  • 固定长度(推荐):达到上限时,StackOverFlowError
  • 动态扩展,当可用内存不足时,OutOfMemoryError(OOM)
  • 实际开发中,尽量不使用动态扩展的方式设置,否则因为某个线程的OOM导致整个服务器资源被耗尽而拖垮其他的服务或者功能(本人遇到过类似的生产问题),简而言之,动态扩展增大了资源调配的控制难度

StackOverFlowError案例演示

public class StackOverFlowError {private static long count = 0;public static void main(String[] args) {test();}public static void test(){count++;System.out.println("正在进行第:" + count + "次调用");test();}}

这是一段自我调用最后造成死循环的调用,最后一定会由于栈内存不足报栈溢出的错误,但是设置不同的栈空间大小,这个count的次数理论上会不一样

以默认的栈空间大小

调大栈内存

通过启动参数配置之后再次运行,可以承受的最大调用次数明显增大了(即栈的深度增大了)

native本地方法栈

我们知道,Java属于上层语言,在对操作系统的控制层面上相比c,c++逊色不少,但是为了实现某些功能需要调用操作系统提供的相关函数,而Java中的native方法的职责就为这一功能的实现提供了一个类似转换的接口

在native方法中,只提供了接口,没有具体的实现,实现部分由C或C++去实现,总结来说:

  • 一个native方法就是一个Java调用非Java代码的接口
  • 定义一个native方法时,并不提供具体的实现
  • native的方法可以调用其他语言接口实现对操作系统更加底层的操作,比如windows下对dll文件的调用

Java虚拟机栈详解相关推荐

  1. JVM(Java虚拟机)详解(JVM 内存模型、堆、GC、直接内存、性能调优)

    JVM(Java虚拟机) JVM 内存模型 结构图 jdk1.8 结构图(极简) jdk1.8 结构图(简单) JVM(Java虚拟机): 是一个抽象的计算模型. 如同一台真实的机器,它有自己的指令集 ...

  2. Java虚拟机组成详解

    一.jvm的主要组成部分 类加载器(ClassLoader) 运行时数据区(Runtime Data Area) 执行引擎(Execution Engine) 本地库接口(Native Interfa ...

  3. JVM(二)Java虚拟机组成详解

    导读:详细而深入的总结,是对知识"豁然开朗"之后的"刻骨铭心",想忘记都难. Java虚拟机(Java Virtual Machine)下文简称jvm,上一篇我 ...

  4. 【JVM】运行时数据区介绍,程序计数器和虚拟机栈详解

    JVM越来越是Java面试中的重头戏,今天来总结一下JVM运行时数据区的相关内容. 文章目录 JVM运行时数据区 JVM运行时数据区内部结构 程序计数器(PC寄存器) 程序计数器的介绍 PC寄存器的实 ...

  5. JVM 虚拟机栈详解

    当Java虚拟机运行程序时.每当一个新的线程被创建时.Java 虚拟机都会分配一个虚拟机栈,Java虚拟机栈是以帧为单位来保存线程的运行状态.Java栈只会有两种操作:以帧为单位进行压栈跟出栈. 某个 ...

  6. 一篇文章了解Java虚拟机,Java虚拟机内存详解

    虚拟机介绍 Java虚拟机(JVM)一种用于计算机设备的规范,可用不同的方式(软件或硬件)加以实现.编译虚拟机的指令集与编译微处理器的指令集非常类似.Java虚拟机包括一套字节码指令集.一组寄存器.一 ...

  7. java虚拟机参数详解

    Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOME\bin\java –option 来启动,-option为虚拟机参数,JAVA_H ...

  8. Java虚拟机结构详解,详细分析其构成

    Java虚拟机 java虚拟机(java virtual machine,JVM),一种能够运行java字节码的虚拟机.作为一种编程语言的虚拟机,实际上不只是专用于Java语言,只要生成的编译文件匹配 ...

  9. Java内存溢出详解之Tomcat配置

    Java内存溢出详解 转自:http://elf8848.iteye.com/blog/378805 一.常见的Java内存溢出有以下三种: 1. java.lang.OutOfMemoryError ...

最新文章

  1. 【iOS-cocos2d-X 游戏开发之十四】cocos2dx(c++)中访问object函数
  2. 剑指offer:和为S的两个数字
  3. 5、HTML块级元素及行内元素
  4. mysql5.7主从
  5. OpenGL环境多维数据集映射
  6. 由胡润百富榜联想到的
  7. 结组项目-四则运算3
  8. .NET开源项目介绍及资源推荐:数据持久层
  9. stucts2 页面上的值如何与Action的属性值对应
  10. 大华工业相机使用说明_大华C900系列SSD | 极速传输,不负美名
  11. PHP不仅仅是PHP
  12. Mac搭建本地服务器及测试demo
  13. 基础集合论 第一章 4 子集
  14. spoon在linux上运行,kettle在linux上运行
  15. openstack进阶:虚拟桌面usb重定向(usb映射)
  16. 腾讯天龙八部手游服务器账号上线,天龙八部手游服务器的注册已达到上限 服务器注册上限怎么解决...
  17. 使用 Python 制作图片和语音验证码
  18. 2019 年度程序员薪酬报告:40 岁以后普遍遭遇收入天花板
  19. Rancher学习日记4
  20. 哈夫曼算法以及求哈夫曼编码

热门文章

  1. 转: ImageMagick 命令行的图片处理工具(客户端与服务器均可用)
  2. 深入浅出 Java 8 Lambda 表达式
  3. 演示对sys用户和普通用户进行审计的示例
  4. ssh 免密登录并用脚本群起服务
  5. Docker 容器的运行(八)
  6. JDBC连接数据库:单线程、多线程、批处理插入数据的对比
  7. DEDECMS给图集图片{dede:productimagelist}自动编号
  8. SQL error: cannot use the special principal 'sa'
  9. curl只能抓取页面的部分内容的原因
  10. Windows Phone 8初学者开发—第6部分:设置应用程序的样式