对线面试官:浅聊一下 Java 虚拟机栈?
对于 JVM(Java 虚拟机)来说,它有两个非常重要的区域,一个是栈(Java 虚拟机栈),另一个是堆。堆是 JVM 的存储单位,所有的对象和数组都是存储在此区域的;而栈是 JVM 的运行单位,它主管 Java 程序运行的。那么为什么它有这样的魔力?它存储的又是什么数据?接下来,我们一起来看。
1.栈定义
我们先来看栈的定义,我们这里的栈指的是 Java 虚拟机栈(Java Virtual Machine Stack)也叫做 JVM 栈,《Java虚拟机规范》对此区域的说明如下:
Each Java Virtual Machine thread has a private Java Virtual Machine stack, created at the same time as the thread. A Java Virtual Machine stack stores frames (§2.6). A Java Virtual Machine stack is analogous to the stack of a conventional language such as C: it holds local variables and partial results, and plays a part in method invocation and return. Because the Java Virtual Machine stack is never manipulated directly except to push and pop frames, frames may be heap allocated. The memory for a Java Virtual Machine stack does not need to be contiguous.
In the First Edition of The Java Virtual Machine Specification, the Java Virtual Machine stack was known as the Java stack.
This specification permits Java Virtual Machine stacks either to be of a fixed size or to dynamically expand and contract as required by the computation. If the Java Virtual Machine stacks are of a fixed size, the size of each Java Virtual Machine stack may be chosen independently when that stack is created.
A Java Virtual Machine implementation may provide the programmer or the user control over the initial size of Java Virtual Machine stacks, as well as, in the case of dynamically expanding or contracting Java Virtual Machine stacks, control over the maximum and minimum sizes.
The following exceptional conditions are associated with Java Virtual Machine stacks:
- If the computation in a thread requires a larger Java Virtual Machine stack than is permitted, the Java Virtual Machine throws a StackOverflowError.
- If Java Virtual Machine stacks can be dynamically expanded, and expansion is attempted but insufficient memory can be made available to effect the expansion, or if insufficient memory can be made available to create the initial Java Virtual Machine stack for a new thread, the Java Virtual Machine throws an OutOfMemoryError.
以上内容翻译成中文的含义如下:
Java 虚拟机栈是线程私有的区域,它随着线程的创建而创建。它里面保存的是局部变量表(基础数据类型和对象引用地址)和计算过程中的中间结果。Java 虚拟机的内存不需要连续,它只有两个操作:入栈和出栈。
Java 虚拟机栈要么大小固定,要么根据计算动态的扩展和收缩。程序员可以对 Java 虚拟机栈进行初始值的大小设置和最大值的设置。
Java 虚拟机栈出现的异常有两种:
当 Java 虚拟机栈大小固定时,如果程序中的栈分配超过了最大虚拟机栈就会出现 StackOverflowError 异常。
如果 Java 虚拟机栈是动态扩展的,那么当内存不足时,就会引发 OutOfMemoryError 的异常。
2.栈结构
栈是线程私有的,每个线程都有自己的栈(空间),栈中的数据是以栈帧(Stack Frame)的形式存在的,线程会为每个正在执行的方法生成一个栈帧,如下图所示:
PS:当一个新的方法被调用时,就会在栈中创建一个栈帧,当方法调用完成之后,也就意味着这个栈帧会执行出栈操作。
而栈帧中又存储了 5 个内容:
- 局部变量表(Local Variables);
- 操作(数)栈(Operand Stack);
- 动态链接(Dynamic Linking);
- 方法返回地址(Return Address);
- 附加信息。
如下图所示:
栈的整体存储结构如下图所示:
2.1 局部变量表
局部变量表也叫做局部变量数组或本地变量表。
局部变量表是一个数组,里面存储的内容有:
- 方法参数;
- 方法内的局部变量,也就是方法内的基本数据类型和对象引用(Reference);
- 方法返回类型(Return Address)。
接下来我们通过类生成的字节码来观察一下局部变量表的内容,首先,我们先来搞一个 main 方法,具体代码如下:
public static void main(String[] args) {
int num = 0;
LocalVariablesExample lv =
new LocalVariablesExample();
}
然后我们编译类,再使用“javap -v LocalVariablesExample.class”查看字节码生成的内容,其中包含的本地变量表内容如下:
我们通过 JClassLib 也能观察到局部变量表的信息,如下图所示为局部变量表的长度:
局部变量表的详细信息如下:
2.2 操作栈
操作栈也叫做操作数栈或表示式栈,操作数栈主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间。
思考:为什么不把程序执行过程中的中间结果保存到局部变量表,而是保存到操作数栈中呢?
因为局部变量表是数组,而数组的长度是在其创建时就要确定,所以局部变量表在编译器就决定内容和大小了,那么在程序执行中的这些动态中间结果,是需要新的空间来保存了,而操作数栈就可以实现此功能。
2.3 动态链接
动态链接也叫做指向运行时常量池的方法引用。
这个区域的概念和作用稍微难理解一点,在每一个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用。当一个方法调用了另外的其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是为了将这些符号引用转换为调用方法的直接引用。
也就是说:当一个方法调用另一个方法时,不会再创建一个被调用的方法,而是通过常量池的方法引用来调用,而这个区域存储的就是运行时常量池的方法引用,这个区域的作用就是将运行时常量池的符号引用转换成直接引用。
2.4 方法返回地址
方法返回地址也叫做方法正常退出或异常退出的定义。
方法返回地址存放的是调用该方法的程序计数器的值。程序计数器里面保存的是该线程要执行的下一行指令的位置。
也就是说:在一个方法中调用了另一个方法,当被调用的方法执行完之后,要执行的下一行指令就是保存在此区域的。
2.5 附加信息
此区域在很多教程上会被省略,因为此区域有可能有数据,也有可能没有数据。这些附加信息是和 Java 虚拟机实现相关的一些信息。例如,对程序调试提供支持的信息。
总结
栈作为 Java 虚拟机中最核心的组成部分之一,它包含了以下 5 部分的内容:
- 局部变量表(Local Variables):主要存储的是方法内的基本数据类型和对象引用;
- 操作(数)栈(Operand Stack):主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间;
- 动态链接(Dynamic Linking):存放的是指向运行时常量池的方法引用;
- 方法返回地址(Return Address):存放的是调用该方法的程序计数器的值;
- 一些附加信息:存储了一些和 Java 虚拟相关的数据,比如程序的调试数据。
参考 & 鸣谢
《阿里巴巴Java开发手册》
《尚硅谷JVM》
本文已收录到 Gitee 开源仓库《Java 面试指南》,其中包含的内容有:Redis、JVM、并发、并发、MySQL、Spring、Spring MVC、Spring Boot、Spring Cloud、MyBatis、设计模式、消息队列等模块。Java 面试有它就够了:超全 Java 常见面试题,持续更新...
对线面试官:浅聊一下 Java 虚拟机栈?的更多相关文章
- 【对线面试官】CountDownLatch和CyclicBarrier的区别
<对线面试官>系列目前已经连载31篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...
- 【对线面试官】Kafka基础入门
<对线面试官>系列目前已经连载33篇啦,这是一个讲人话面试系列 [对线面试官]Java注解 [对线面试官]Java泛型 [对线面试官] Java NIO [对线面试官]Java反射 &am ...
- 【对线面试官】Java NIO
服务端: public class NoBlockServer { public static void main(String[] args) throws IOException { // 1.获 ...
- 【对线面试官】Java 反射&&动态代理
// 抽象类,定义泛型<T> public abstract class BaseDao<T> { public BaseDao(){ Class clazz = this.g ...
- 【对线面试官】Java多线程基础
// 请求直接交给线程池来处理 public void push(PushParam pushParam) { try { pushServiceThreadExecutor.submit(() -& ...
- 浅谈MySQL日志文件|手撕MySQL|对线面试官
关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 上周五面试了字节的第三面,深感数据库知识的重要,我也意识到在平时的学习中,自己对于数据库的学习较为薄弱.甚至在有过一定实习经验之后,依旧因为 ...
- 面试官:为什么需要Java内存模型?
面试官:今天想跟你聊聊Java内存模型,这块你了解过吗? 候选者:嗯,我简单说下我的理解吧.那我就从为什么要有Java内存模型开始讲起吧 面试官:开始你的表演吧. 候选者:那我先说下背景吧 候选者:1 ...
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...
- 【Java面试宝典】深入理解JAVA虚拟机
一.运行时数据区域 线程隔离:线程隔离的意思,就是给不同的线程多分配的资源用,以做到不争用. 线程共享:线程共享就是资源只有一个没有办法分配更多,只能共享. Java虚拟机管理的内存包括几个运行时数据 ...
- Java虚拟机栈(java stack)
虚拟机栈(java stack) 百度图片搜索里的动图搜索功能不错,可以搜索一些动图,展示操作数栈的操作过程,比较形象.这点google差点意思 虚拟机栈(jvm stacks)是线程独占的 里面是多 ...
随机推荐
- Dubbo-聊聊通信模块设计
前言 Dubbo源码阅读分享系列文章,欢迎大家关注点赞 SPI实现部分 Dubbo-SPI机制 Dubbo-Adaptive实现原理 Dubbo-Activate实现原理 Dubbo SPI-Wrap ...
- 顺序表代码总结——SqList
在C++编译器下可直接运行 #include <stdio.h> #include <stdlib.h> #include <malloc.h> //顺序表存储结构 ...
- python(牛客)试题解析1 - 简单
导航: 一.NC103 反转字符串 二.NC141 判断是否为回文字符串 三.NC151 最大公约数 四.NC65 斐波那契数列 五.字符按排序后查看第k个最小的字母 六.数组内取出下标相同的元素求和 ...
- tcp网络交互的理解 以及代码实现
服务端 import socketserver = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind(("127.0. ...
- [ERROR] mariadbd: The table 'INNODB_BUFFER_PAGE' is full
问题描述:将information_schema导出sql文件到新库中恢复,sql中的表都是临时表,存储引擎都是memory,在导入的过程中实际大量会占用临时表. 报错信息:ERROR 1114 (H ...
- AcWing第78场周赛
今天想起来了,就补一下吧~ 第一题 商品分类 货架中摆放着 n 件商品,每件商品都有两个属性:名称和产地. 当且仅当两件商品的名称和产地都相同时,两件商品才视为同一种商品. 请你统计,货架中一共有多少 ...
- python实现AES加密解密
1. 前言 AES是一种对称加密,所谓对称加密就是加密与解密使用的秘钥是一个. 之前写过一片关于python AES加密解密的文章,但是这里面细节实在很多,这次我从 参数类型.加密模式.编码模式.补全 ...
- 关于pip3 ImportError: cannot import name 'main'的报错的原因及解决办法
这个问题的出现大多数都是因为你用错误的方法去升级pip3导致的 先来说一下正确的升级方法: python3 -m pip install --upgrade pip 我发现升级后版本变为了 19.x, ...
- HCIE Routing&Switching之MPLS基础理论
技术背景 90年代初期,互联网流量快速增长,而由于当时硬件技术的限制,路由器采用最长匹配算法逐跳转发数据包,成为网络数据转发的瓶颈:于是快速路由技术成为当时研究的一个热点:在各种方案中,IETF确定了 ...
- 一文教会你如何在内网搭建一套属于自己小组的在线 API 文档?
Hello,大家好,我是阿粉,对接文档是每个开发人员不可避免都要写的,友好的文档可以大大的提升工作效率. 阿粉最近将项目的文档基于 Gitbook 和 Gitlab 的 Webhook 功能的在内网部 ...