1. 概念

Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,栈使用的内存不需要保证是连续的,栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。

Java虚拟机规范即允许Java虚拟机栈被实现成固定大小(-Xss),也允许通过计算结果动态来扩容和收缩大小。如果采用固定大小的Java虚拟机栈,那每个线程的Java虚拟机栈容量可以在线程创建的时候就已经确定,并写入方法表的Code属性之中。

Java虚拟机以方法作为最基本的执行单元,“栈帧”(Stack Frame)则是用于支持虚拟机进行方法调用和方法执行背后的数据结构,它也是虚拟机运行时数据区中的虚拟机栈(Virtual Machine Stack)的栈元素。栈帧存储了方法的局部变量表操作数栈动态连接方法返回地址等信息。

在运行时的线程中,只有当前栈帧有效(Java虚拟机栈中栈顶的栈帧),与当前栈帧相关联的方法称为当前方法。每调用一个新的方法,被调用方法对应的栈帧就会被放到栈顶(入栈),也就是成为新的当前栈帧。当一个方法执行完成退出的时候,此方法对应的栈帧也相应销毁(出栈)。

2. 局部变量表

2.1变量槽

局部变量表的容量以变量槽(Variable Slot)为最小单位,不过Java虚拟机规范中并没有明确规定每个Slot所占据的内存空间大小。Java虚拟机规范允许Slot的长度可以随着处理器、操作系统或者虚拟机的不同而发生变化。对于64位的数据类型,虚拟机会以高位在前的方式为其分配两个连续的Slot空间。即long和double两种类型。做法是将long和double类型速写分割为32位读写的做法,使用第n和第n+1两个Slot来表示。

2.2 局部变量表特性

如果是实例方法(非static方法),那么局部变量表中的第0位索引的Slot默认是用来传递方法所属对象实例的引用,在方法中可以通过关键字this来访问这个隐含的参数。其余参数按照参数表的顺序来排列,占用从1开始的局部变量Slot,参数表分配完毕后,再根据方法体内部定义的变量顺序和作用域分配其余的Slot。简而言之如图所示,static方法在变量表中没有this参数,实例方法有this,且序号靠前。

局部变量表中的Slot是可重用的,方法体中定义的变量,其作用域并不一定会覆盖整个方法体,如果当前字节码程序计数器的值已经超过了某个变量的作用域,那么这个变量相应的Slot就可以交给其他变量去使用,节省栈空间,但也有可能会影响到系统的垃圾收集行为。局部变量在使用完以后它的槽会让给其他变量重复使用。如图中b变量的槽使用完后,c变量也使用了序号2的槽,达到了节约空间的效果。

变量槽的重复使用会影响垃圾收集行为,在垃圾收集时候会对象无法回收的情况情况。如图中左为回收对象失败,经过修改后如图中右边顺利回收了对象。

placeholder能否被回收的根本原因就是:局部变量表中的变量槽是否还存有关于placeholder数组对象的引用。首先需要代码离开了placeholder的作用域。但由于没有发生过任何对局部变量表的读写操作,placeholder原本所占用的变量槽还没有被其他变量所复用,所以作为GC Roots一部分的局部变量表仍然保持着对它的关联。这种关联没有被及时打断,绝大部分情况下影响都很轻微。但如果遇到一个方法,其后面的代码有一些耗时很长的操作,而前面又定义了占用了大量内存但实际上已经不会再使用的变量,手动将其设置为null值(用来代替那句int a=0,把变量对应的局部变量槽清空)。

3. 操作数栈

操作数栈(Operand Stack)也常称为操作栈,它是一个后入先出栈(LIFO)。同局部变量表一样,操作数栈的最大深度也在编译的时候写入到方法的Code属性的max_stacks数据项中

另外在概念模型中,两个不同栈帧作为不同方法的虚拟机栈的元素,是完全相互独立的。但是在大多虚拟机的实现里都会进行一些优化处理,令两个栈帧出现一部分重叠。让下面栈帧的部分操作数栈与上面栈帧的部分局部变量表重叠在一起,这样做不仅节约了一些空间,更重要的是在进行方法调用时就可以直接共用一部分数据,无须进行额外的参数复制传递了,重叠的过程如图所示。

4.动态链接

Class文件的常量池中存有大量的符号引用,字节码中的方法调用指令就以常量池里指向方法的符号引用作为参数。这些符号引用一部分会在类加载阶段或者第一次使用的时候就被转化为直接引用,这种转化被称为静态解析。另外一部分将在每一次运行期间都转化为直接引用,这部分就称为动态连接。动态链接保存的是指向方法区常量池中该方法的引用。

5.方法返回地址

对象引用(reference类型,它并不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或者其他与此对象相关的位置)和returnAddress类型(指向了一条字节码指令的地址)。

6.本地方法栈

本地方法栈的功能和特点类似于虚拟机栈,均具有线程隔离的特点以及都能抛出StackOverflowError和OutOfMemoryError异常。本地方法栈服务的对象是JVM执行的native方法,其就是一个java调用非java代码的接口,作用是与操作系统和外部环境交互。

如果某个虚拟机实现的本地方法接口是使用C连接模型的话,那么它的本地方法栈就是C栈。当C程序调用一个C函数时,其栈操作都是确定的。传递给该函数的参数以某个确定的顺序压入栈,它的返回值也以确定的方式传回调用者。同样,这就是虚拟机实现中本地方法栈的行为。

7.程序计数器

程序计数器,(Program Counter Register)每一个线程都有唯一对应的程序计数器是线程私有的,它内存空间小,几乎可以忽略不记,是运行速度最快的存储区域。如图2-1所示,程序计数器是一个记录着当前线程所执行的字节码的行号指示器

[JVM] Java虚拟机栈相关推荐

  1. [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义...

    前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine  ,既然是虚拟机, ...

  2. 12.JDK1.8 JVM运行时数据区域概览、各区域介绍、程序计数器、Java虚拟机栈、本地方法栈、堆、堆空间内存分配(默认情况下)、字符串常量池、元数据区、jvm参数配置

    12.JDK1.8 JVM运行时数据区域概览 12.1.JDK1.8 JVM运行时数据区域概览 12.2.各区域介绍 12.3.各区域介绍 12.3.1.程序计数器 12.3.2.Java虚拟机栈 1 ...

  3. Java必突-JVM知识专题(一): Java代码是如何跑起来的+类加载到使用的过程+类从加载到使用核心阶段(类初始化)+类加载的层级结构+什么是JVM的内存区域划分?Java虚拟机栈、Java堆内存

    前言: 该章节知识点梳理:本文主要是入门和了解jvm,不做深入 1.Java代码是如何运行起来的? 2.类加载到使用的过程? 3.验证准备和初始化的过程? 4.类从加载到使用核心阶段:初始化.类加载器 ...

  4. 【深入理解JVM】运行时数据区域:java虚拟机栈

    虚拟机栈是线程私有,生命周期与线程相同. java虚拟机栈描述的是Java方法执行的线程内存模型: 每个方法在执行的时候,Java虚拟机栈都会同步创建一个栈帧(stack frame),用于 储存 局 ...

  5. 探究Java虚拟机栈

    前言 Java 虚拟机的内存模型分为两部分:一部分是线程共享的,包括 Java 堆和方法区:另一部分是线程私有的,包括虚拟机栈和本地方法栈,以及程序计数器这一小部分内存.今天我就 Java 虚拟机栈做 ...

  6. 46栈内存溢出、内存区域(程序计数器、Java 虚拟机栈、本地方法栈、Java 堆、方法区、直接内存、内存溢出)与内存溢出(对象实例化分析)

    46.什么情况下会发生栈内存溢出 46.1.Java 内存区域与内存溢出 46.1.1.内存区域 46.1.1.1.程序计数器 46.1.1.2.Java 虚拟机栈 46.1.1.3.本地方法栈 46 ...

  7. JVM程序计数器,虚拟机栈,本地方法栈

    程序计数器 它记录了程序执行字节码的行号和指令,字节码解释器的工作就是改变程序计数器的值,切换下一条需要执行的指令(分支,循环,跳转,异常等).java虚拟机是多线程通过轮流切换CPU时间片的方式实现 ...

  8. java虚拟机栈(亦篇足以,吴懈可击)

    文章目录 前言 一.虚拟机栈的概述 1.虚拟机栈出现的背景 2.虚拟机栈的概述 3.虚拟机栈中的常见异常 二.栈的存储单位 ※局部变量表 1.局部变量表概况 2. 变量槽Slot 3.局部变量和成员变 ...

  9. JAVA虚拟机栈的主要特点

    虚拟机栈出现的背景 由于夸平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 优点是跨平台,指令集小,编译器荣耀实现,缺点是性能下降,实现同样的功能需 ...

  10. Java虚拟机--Java虚拟机栈

    文章引用: 1 <深入理解Java虚拟机> 2 https://www.cnblogs.com/niejunlei/p/5987611.html 3 https://blog.csdn.n ...

最新文章

  1. Python_面向对象_类1
  2. 微信小程序Java登录流程(ssm实现具体功能和加解密隐私信息问题解决方案)
  3. linux基础篇-系统中进程相关概念
  4. 在什么时候需要使用“常引用”?
  5. Maven build中隐藏的SAP UI5 JavaScript merge任务
  6. java设置属性的取值范围是多少_jvm-Java系统属性的范围
  7. uefi引导linux_使用UEFI双重引导Windows和Linux
  8. es6 模块的整体加载
  9. Java中equals()方法和==的区别分析
  10. 基于8086CPU微处理器的汇编学习之内存空间的编辑
  11. 【深度优先搜索】计蒜客:等边三角形
  12. android ui设计最新字体,UI设计常用字体规范
  13. 游戏开发需要懂几种语言?
  14. 张一鸣:我的大学四年收获及工作感悟
  15. 生产者消费者的几种写法
  16. keil 中 warning: #1-D: last line of file ends without a newline的解决办法
  17. 为什么要经常更换无轴螺旋输送机叶片?
  18. BigDecimal 金额转换
  19. 《无人机通信与导航技术》札记
  20. 【错误记录】Ubuntu 下 VSCode 编译报错 ( 无法生成和调试,因为活动文件不是 C 或 C++ 源文件。终端进程启动失败(退出代码: -1)。终端将被任务重用,按任意键关闭。 )

热门文章

  1. IIS6同一IP部署多域名证书(部署指南)
  2. linux远程映射usb设备,Linux 系统下USB端口映射
  3. c语言程序设计辅导资料pdf,C语言程序设计辅导资料(修订版).pdf
  4. 阶乘的java编程_java编程求n的阶乘
  5. 高德地图,百度地图坐标系GPS的转化
  6. 钣金编程软件Radan无人值守,自动排版功能
  7. java 邮件发送乱码_java邮件发送乱码解决方法
  8. 单日暴跌60%,崩盘4次的AMPL,这次还能回来吗?
  9. 三个参数 matlab程序,用matlab求定积分的三个实例代码
  10. python pyqt5浏览器_全网最简明的PyQt 5 教程,神级Python现场开发一个专属浏览器!...