深入理解JVM-java虚拟机栈
1.java虚拟机栈

1. Java虚拟机栈也是线程私有的,它的生命周期与线程相同(随线程而生,随线程而灭)
2. 如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;
如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常;
(当前大部分JVM都可以动态扩展,只不过JVM规范也允许固定长度的虚拟机栈)
3. Java虚拟机栈描述的是Java方法执行的内存模型:每个方法执行的同时会创建一个栈帧。
对于我们来说,主要关注的stack栈内存,就是虚拟机栈中局部变量表部分。
2.栈帧(Stack Frame)
栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。它是虚拟机运行时数据区中的java虚拟机栈的栈元素。
栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。
每一个方法从调用开始至执行完成的过程,都对应着一个栈帧在虚拟机里面从入栈到出栈的过程。
注意:
在编译程序代码的时候,栈帧中需要多大的局部变量表内存,多深的操作数栈都已经完全确定了。 因此一个栈帧需要分配多少内存,不会受到程序运行期变量数据的影响,而仅仅取决于具体的虚拟机实现。
栈结构图如下:

注意:
在活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧相关联的方法称为当前方法。
执行引擎运行的所有字节码指令都只针对当前栈帧进行操作。
3.局部变量表
1.局部变量表(Local Variable Table)是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。
并且在Java编译为Class文件时,就已经确定了该方法所需要分配的局部变量表的最大容量。
2.局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)「String是引用类型」,
对象引用(reference类型) 和 returnAddress类型(它指向了一条字节码指令的地址)
注意:
很多人说:基本数据和对象引用存储在栈中。
当然这种说法虽然是正确的,但是很不严谨,只能说这种说法针对的是局部变量。
局部变量存储在局部变量表中,随着线程而生,线程而灭。并且线程间数据不共享。
但是,如果是成员变量,或者定义在方法外对象的引用,它们存储在堆中。
因为在堆中,是线程共享数据的,并且栈帧里的命名就已经清楚的划分了界限 : 局部变量表!
4.变量槽(Variable Slot)
局部变量表的容量以变量槽为最小单位,每个变量槽都可以存储32位长度的内存空间,例如boolean、byte、char、short、int、float、reference。
对于64位长度的数据类型(long,double),虚拟机会以高位对齐方式为其分配两个连续的Slot空间,也就是相当于把一次long和double数据类型读写分割成为两次32位读写。
扩展知识点:
Slot复用 为了尽可能节省栈帧空间,局部变量表中的Slot是可以重用的,
也就是说当PC计数器的指令指已经超出了某个变量的作用域(执行完毕),
那这个变量对应的Slot就可以交给其他变量使用。 优点 : 节省栈帧空间。 缺点 : 影响到系统的垃圾收集行为。 (如大方法占用较多的Slot,执行完该方法的作用域后没有对Slot赋值或者清空设置null值,垃圾回收器便不能及时的回收该内存。)
5.reference(对象实例的引用)
我的理解是:一个超链接
一般来说,虚拟机都能从引用中直接或者间接的查找到对象的以下两点 :
a.在Java堆中的数据存放的起始地址索引。
b.所属数据类型在方法区中的存储类型。
例如:我们在创建一个Student对象时的数据存储结构:

6.动态连接
每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,
持有这个引用是为了支持方法调用过程中的动态连接(Dynamic Linking)。
在类加载阶段中的解析阶段会将符号引用转为直接引用,这种转化也称为静态解析。
另外的一部分将在每一次运行时期转化为直接引用。这部分称为动态连接。
这里简单提一下动态连接的概念,后面在详细讲解.
7.方法出口
当一个方法开始执行后,只有2种方式可以退出这个方法 :
方法返回指令 : 执行引擎遇到一个方法返回的字节码指令,这时候有可能会有返回值传递给上层的方法调用者,这种退出方式称为正常完成出口。
异常退出 : 在方法执行过程中遇到了异常,并且没有处理这个异常,就会导致方法退出。
无论采用任何退出方式,在方法退出之后,都需要返回到方法被调用的位置,程序才能继续执行,方法返回时可能需要在栈帧中保存一些信息。
一般来说,方法正常退出时,调用者的PC计数器的值可以作为返回地址,栈帧中会保存这个计数器值。
而方法异常退出时,返回地址是要通过异常处理器表来确定的,栈帧中一般不会保存这部分信息。
8.实战案例
如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常
package com.wfd360.demo01; /**
* @Copyright (C)
* @Author: LI DONG PING
* @Date: 2019-07-15 17:17
* @Description: 栈内存溢出测试
* <p>
* 测试代码设计思路
* 修改默认堆栈大小后,利用递归调用一个方法,达到栈深度过大的异常目的,同时在递归调用过程中记录调用此次,得出最大深度的数据
* jvm参数
* -Xss 180k:设置每个线程的堆栈大小(最小180k),默认是1M
*/
public class TestStackOverflowErrorDemo {
//栈深度统计值
private int stackLength = 1; /**
* 递归方法,导致栈深度过大异常
*/
public void stackLeak() {
stackLength++;
stackLeak();
} /**
* 启动方法
* 测试结果:当-Xss 180k为180k时,stackLength~=1544,随着-Xss参数变大时stackLength值随之变大
* @param args
*/
public static void main(String[] args) {
TestStackOverflowErrorDemo demo = new TestStackOverflowErrorDemo();
try {
demo.stackLeak();
} catch (Throwable e) {
System.out.println("当前栈深度:stackLength=" + demo.stackLength);
e.printStackTrace();
}
}
}
测试结果:

完美!
深入理解JVM-java虚拟机栈的更多相关文章
- 深入学习重点分析java基础---第一章:深入理解jvm(java虚拟机) 第一节 java内存模型及gc策略
身为一个java程序员如果只会使用而不知原理称其为初级java程序员,知晓原理而升中级.融会贯通则为高级 作为有一个有技术追求的人,应当利用业余时间及零碎时间了解原理 近期在看深入理解java虚拟机 ...
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- Java JVM——5.Java虚拟机栈
虚拟机栈概述 由于跨平台性的设计,Java 的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 栈实现的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样的功 ...
- JVM 运行时数据区:程序计数器、Java 虚拟机栈和本地方法栈,方法区、堆以及直接内存
Java 虚拟机可以看作一台抽象的计算机,如同真实的计算机,它也有自己的指令集和运行时内存区域. Java 虚拟机在执行 Java 程序的过程中会把它所管理的内存(运行时内存区域)划分为若干个不同的数 ...
- JVM运行时数据区--Java虚拟机栈
虚拟机栈的背景 由于跨平台性的设计,java的指令都是根据栈来设计的.不同平台CPU架构不同,所以不能设计为基于寄存器的. 根据栈设计的优点是跨平台,指令集小,编译器容易实现,缺点是性能下降,实现同样 ...
- java虚拟机栈(关于java虚拟机内存的那些事)
<深入理解 java 虚拟机> 读书扩展 作者:淮左白衣 写于 2018年4月13日16:26:51 目录 文章目录 java虚拟机栈是什么 特点 栈帧 局部变量表 什么时候抛出 `Sta ...
- Java虚拟机栈 和 方法区 的联系
1.Java虚拟机栈 java方法执行时的内存模型 1.1 栈帧 每个方法都会在虚拟机栈中创建一个对应的栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息. 一个方法的调用到结束就对应这一个 ...
- 深入理解JVM - Java内存区域与内存溢出异常 - 第二章
一 运行时数据区域 JVM在执行Java程序的过程中会把它管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途,以及创建和销毁的时间. 程序计数器 程序计数器(Program Counter ...
- java虚拟机栈 相关操作
针对JVM虚拟栈 和栈帧的操作 虚拟机栈: 栈元素是栈帧.方法调用,栈帧入栈,反之出栈. 栈帧:一个方法的运行空间. 1.局部变量表:方法定义的局部变量.方法的参数存在该表. 实例方法中有个隐含参数“ ...
- Java虚拟机栈(java stack)
虚拟机栈(java stack) 百度图片搜索里的动图搜索功能不错,可以搜索一些动图,展示操作数栈的操作过程,比较形象.这点google差点意思 虚拟机栈(jvm stacks)是线程独占的 里面是多 ...
随机推荐
- css3特效插件wow.js
在使用css3写特效的时候,会遇到比较麻烦的就是css3代码需要大量的调试,但是现在有了wow.js,让写特效变得简单了很多. wow.js官网 https://www.delac.io/wow/in ...
- PHP打印日志类
PHP简单封装个打印日志类,方便查看日志: <?php /** * Created by PhpStorm. * User: zenkilan * Date: 2019/9/26 * Time: ...
- Ajax验证
import javax.servlet.http.HttpServletRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactor ...
- 【错误解决】git报错:you are not allowed to push code to protected branches on this project
场景回忆: 本地修改需要退回到之前的版本,打算强制push本地版本覆盖远程版本,但是在git push --force后出现了以下的错误: Fix GitLab error: "you ar ...
- Nginx打印json日志
1.修改配置,在http{}中添加 log_format access_json '{"@timestamp":"$time_iso8601",' '" ...
- iOS开发 判定某个时间是否属于这个时间段
- (BOOL)isBetweenDate { //设置的是中国时间 NSString *startTime=@"13:01"; NSString *expireTime=@&qu ...
- EasyDSS高性能RTMP、HLS(m3u8)、HTTP-FLV、RTSP流媒体服务器和EasyDSS云平台异同
背景分析 不同于EasyDSS流媒体服务器与EasyDSS流媒体解决方案(EasyDSS流媒体解决方案就是通过EasyDSS流媒体服务器完善业务层研发而来),EasyDSS流媒体服务器和EasyDSS ...
- zuul 熔断后重试
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring ...
- 【记录】【solr】solr7.2.1原子更新
就是说只更新指定的字段,没有的字段则添加,有的字段则替换,没有指定更新的字段不会被删除 原来的数据只有id和name这两个字段 java操作,更新一个字段,id用于指定数据 结果,name字段没有被删 ...
- jquery关于on click事件的理解
jquery关于on click事件的理解 <pre><a style="min-width:60px; margin-left:6px;" wenzhangid ...