Java 虚拟机栈详解分析

Java虚拟机栈

1. 定义

  • 栈:线程运行时需要的内存空间,一个栈存在多个栈帧。栈具有先入后出,后入先出的特点。
  • 栈帧:每个方法运行时需要的内存(局部变量表、操作数栈、动态链接和方法返回值等信息。),每次调用一个方法,便会将栈帧压入栈中,方法执行完毕将栈帧从栈顶压出
  • 活动栈帧:指在栈顶的栈帧,既正在调用的方法,每个线程只能有一个活动栈帧,对应着该线程正在调用的那个方法

现在我们用代码来演示一下Java虚拟机如何将栈帧压入及压出栈中

 public class Main {
     public static void main(String[] args) {
         method1();
     }

     private static void method1() {
         method2(1, 2);
     }

     private static int method2(int a, int b) {
         int c = a + b;
         return c;
     }
 }

当我们运行Main函数时,jvm首先将栈帧Main压入栈中,此视栈结构如图所示

Main函数体中调用了method1方法,此时便会将栈帧1压入栈中

method1方法体中调用了method2方法,这时jvm会将栈帧2压入栈结构中,需要注意的是,前面我们提到了栈帧由 “局部变量表、操作数栈、动态链接和方法返回值”等信息组成,method2方法中拥有a,b两个参数以及局部变量c和方法返回值

当method2方法执行完后,会将栈帧2从栈顶弹出

method1方法执行完毕后,将栈帧1弹出

依次顺序直至线程被销毁。

注意点

  • 由于每个栈帧都会在方法调用完毕后被弹出,因此栈内存不需要进行垃圾回收
  • 每个栈都是线程私有的,每个线程在创建的时候都会创建一个虚拟机栈,而由于物理内存是固定的,栈内存划分得越大,可分配的线程数就越少

2. 栈的线程安全问题

局部变量是线程安全的

现在我们定义如下方法:

 public static void method() {
     int a = 0;
     a++;
 }

我们在方法method中定义了一个局部变量a,并对其执行a++操作,现在假设我们有两个线程同时调用了这个方法(栈帧),Java虚拟机会将该栈帧压入各自线程的栈内存中,但由于局部变量表是线程私有的,所以两个线程在同时调用这个栈帧后,a的值仍然都为1,故局部变量是线程安全的

方法参数和方法返回值不是线程安全

由于方法的参数和返回值均可被外部方法所引用,故在某个线程下某个方法可以更改另外一个方法的参数和返回值,故方法参数和方法返回值不是线程安全的

3. 栈内存溢出

由于程序执行时,虚拟机给每个栈分配的栈内存空间是固定的,所以在一些情况下有可能出现栈内存空间不足,导致溢出的情况,一般有两种情况可能导致栈内存溢出

  • 栈帧过大(较少出现)
  • 栈帧过多(一般出现在递归时。没有正确设置递归出口)

现在我们来解释一下什么时候会出现栈帧过多导致栈内存溢出,我们来假设某一个栈的内存空间大小是1024kb,现在有四个栈帧,每个栈帧的大小均为300kb,而 300 * 4 = 1200kb, 而 1200 > 1024 ,很显然,现在这四个栈帧合起来的大小已经超过了这个栈的内存空间大小,这个时候就会出现栈内存溢出,也就是会报java.lang.StackOverflowError这个错误。

到此这篇关于Java 虚拟机栈详解分析的文章就介绍到这了,更多相关Java 虚拟机栈内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java内存模型中的虚拟机栈原理分析

    Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都会有各自的用途,以及创建和销毁的时间,有的区域会随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁.Java虚拟机所管理的内存将会包括以下几个运行时数据区域.如下图所示(图片来自<深入理解Java虚拟机>一书). 在内存中,栈分为两部分,一部分是本地方法栈,为虚拟机使用到的Native方法服务,具体的虚拟机可以自由实现,另一部分就是虚拟机栈,主要是为虚拟机执行Java方法服务

  • 详解java中jvm虚拟机栈的作用

    jvm虚拟机栈的作用 jvm虚拟机栈栈帧的组成 jvm虚拟机栈,也叫java栈,它由一个个的栈帧组成,而栈帖由以下几个部分组成 局部变量表-存储方法参数,内部使用的变量 操作数栈-在变量进行存储时,需要进行入栈和出栈 动态连接-引用类型的指针 方法出口-方法的返回 一段原程序代码 package com.lind.basic; public class Demo1 { static int hello() { int a = 1; int b = 2; int c = a + b; return

  • java虚拟机中栈的运行知识点总结

    运行原理 1.不同线程中所包含的栈帧是不允许存在相互引用的. 2.如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回此方法的执行结果给当前一个栈针,并且虚拟机会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧. 3.Java方法有两种返回函数的方式,一种是正常的函数返回,使用return指令:另一种是抛出异常.不管使用哪种方式,都会导致栈帧被弹出. 实例 public class StackFrameTest { public static void main(String[] args) {

  • 深入了解Java虚拟机栈以及内存模型

    1.结合字节码指令理解Java虚拟机栈和栈帧 栈帧:每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间. 每个栈帧中包括局部变量表(Local Variables).操作数栈(Operand Stack).指向运行时常量池的引用(A reference to the run-time constant pool).方法返回地址(Return Address)和附加信息. 局部变量表:方法中定义的局部变量以及方法的参数存放在这张表中,局部变量表中的变量不可直接使用,如需要使用的话,必须通过

  • Java虚拟机运行时栈的栈帧

    目录 Java虚拟机栈概述 局部变量表 操作数栈 动态连接 方法的返回地址 结合javap命令理解栈帧 Java虚拟机栈概述 Java虚拟机栈(Java Virtual Machine Stacks)是线程私有的,它的生命周期与线程相同.虚拟机栈描述的是Java方法执行的内存模型:栈帧(Stack Frame)是用于支持Java虚拟机进行方法调用和执行的数据结构,它是虚拟机栈中的栈元素.每个方法在执行的同到都会创建一个栈帧用于存储局部变量表.操作数栈.动态链接.方法出口等信息. 在编译程序代码的

  • Java 虚拟机栈详解分析

    Java虚拟机栈 1. 定义 栈:线程运行时需要的内存空间,一个栈存在多个栈帧.栈具有先入后出,后入先出的特点. 栈帧:每个方法运行时需要的内存(局部变量表.操作数栈.动态链接和方法返回值等信息.),每次调用一个方法,便会将栈帧压入栈中,方法执行完毕将栈帧从栈顶压出 活动栈帧:指在栈顶的栈帧,既正在调用的方法,每个线程只能有一个活动栈帧,对应着该线程正在调用的那个方法 现在我们用代码来演示一下Java虚拟机如何将栈帧压入及压出栈中 public class Main { public stati

  • PHP和Java 集成开发详解分析 强强联合第1/4页

    时间一天天过去,这两个亮点也变得越来越亮,很快,它们受到了编程者的喜欢,于是有人有疑问了:要是它们两者相遇,会发生什么事情?有没有可能将它们的强项结合在一起呢? 尝试在PHP和Java之间搭建一座桥梁,利用这座桥梁在这两个实体之间建立起一个沟通渠道,在这座桥梁的帮助下,你可以在Java中开发类,然后在PHP中调用它们的方法,同样,在你的Java桌面或Web应用程序中也可以使用PHP脚本. 在这篇文章中,你将会学到如何: ◆安装和配置PHP/Java桥 ◆在PHP脚本中使用Java类 ◆在Java

  • Java List 用法详解及实例分析

    Java List 用法详解及实例分析 Java中可变数组的原理就是不断的创建新的数组,将原数组加到新的数组中,下文对Java List用法做了详解. List:元素是有序的(怎么存的就怎么取出来,顺序不会乱),元素可以重复(角标1上有个3,角标2上也可以有个3)因为该集合体系有索引 ArrayList:底层的数据结构使用的是数组结构(数组长度是可变的百分之五十延长)(特点是查询很快,但增删较慢)线程不同步 LinkedList:底层的数据结构是链表结构(特点是查询较慢,增删较快) Vector

  • Java Mybatis框架多表操作与注解开发详解分析

    目录 一对一查询 多对多查询 Mybatis的注解开发 Mybatis的增删查改 MyBatis的注解实现复杂映射开发 一对一查询 一对一查询的模型 用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户. 一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户 一对一查询的语句 对应的sql语句: select * from orders o,user u where o.uid=u.id;查询的结果如下: 创建Order和User实体 创建OrderMapper接口 p

  • Java Mybatis框架Dao层的实现与映射文件以及核心配置文件详解分析

    目录 Mybatis的Dao层实现 传统开发方式 代理开发方式 MyBatis映射文件深入 动态sql语句 动态SQL之<if> 动态SQL之<foreach> SQL片段抽取 总结 Mybatis核心配置文件深入 typeHandlers标签 plugins标签 总结 Mybatis的Dao层实现 传统开发方式 1.编写UserDao接口 public interface UserMapper { public List<User> findAll() throws

  • Java SpringMVC拦截器与异常处理机制详解分析

    目录 拦截器(interceptor)的作用 拦截器快速入门 案例:用户登录权限控制 拦截器方法说明 SpringMVC异常处理 异常处理的思路 异常处理两种方式 拦截器(interceptor)的作用 Spring MVC的拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理. 将拦截器按一定的顺序联结成一条链,这条链称为拦截器链(Interceptor Chain).在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用.拦截器也是AOP思

  • Java并发编程之Volatile变量详解分析

    目录 一.volatile变量的特性 1.1.保证可见性,不保证原子性 1.2.禁止指令重排 二.内存屏障 三.happens-before Volatile关键字是Java提供的一种轻量级的同步机制.Java 语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量, 相比synchronized(synchronized通常称为重量级锁),volatile更轻量级,因为它不会引起线程上下文的切换和调度. 但是volatile 变量的同步性较差(有时它更简单并且开销更低),而且其

  • java 多线程与并发之volatile详解分析

    目录 CPU.内存.缓存的关系 CPU缓存 什么是CPU缓存 为什么要有多级CPU Cache Java内存模型(Java Memory Model,JMM) JMM导致的并发安全问题 可见性 原子性 有序性 volatile volatile特性 volatile 的实现原理 总结 CPU.内存.缓存的关系 要理解JMM,要先从计算机底层开始,下面是一份大佬的研究报告 计算机在做一些我们平时的基本操作时,需要的响应时间是不一样的!如果我们计算一次a+b所需要的的时间: CPU读取内存获得a,1

  • Java Spring Boot消息服务万字详解分析

    目录 消息服务概述 为什么要使用消息服务 异步处理 应用解耦 流量削峰 分布式事务管理 常用消息中间件介绍 ActiveMQ RabbitMQ RocketMQ RabbitMQ消息中间件 RabbitMQ简介 RabbitMQ工作模式介绍 Work queues(工作队列模式) Public/Subscribe(发布订阅模式) Routing(路由模式) Topics(通配符模式) RPC Headers RabbitMQ安装以及整合环境搭建 安装RabbitMQ 下载RabbitMQ 安装R

  • Java 逻辑控制详解分析

    目录 顺序结构 分支结构 if 语句 悬垂 else 问题 switch 语句 循环结构 while 循环 break continue for循环 do while 循环 顺序结构 顺序结构就是按照代码从上往下执行,我们运行的程序就是从上往下的顺序结构,当遇到方法的时候,才去执行方法.例如: System.out.println("aaa"); System.out.println("bbb"); System.out.println("ccc"

随机推荐