Java虚拟机栈jvm栈的作用

作者:小小奶酪可笑可笑 时间:2023-11-10 13:52:15 

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压入栈中,此视栈结构如图所示 

Java虚拟机栈jvm栈的作用

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

Java虚拟机栈jvm栈的作用

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

Java虚拟机栈jvm栈的作用

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

Java虚拟机栈jvm栈的作用

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

Java虚拟机栈jvm栈的作用

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

注意点

  • 由于每个栈帧都会在方法调用完毕后被弹出,因此栈内存不需要进行垃圾回收

  • 每个栈都是线程私有的,每个线程在创建的时候都会创建一个虚拟机栈,而由于物理内存是固定的,栈内存划分得越大,可分配的线程数就越少

2. 栈的线程安全问题

局部变量是线程安全的

现在我们定义如下方法:


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

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

Java虚拟机栈jvm栈的作用

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

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

3. 栈内存溢出

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

  • 栈帧过大(较少出现)

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

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

Java虚拟机栈jvm栈的作用

来源:https://blog.csdn.net/qq1104380920/article/details/121199089

标签:Java,jvm栈
0
投稿

猜你喜欢

  • SpringBoot统一返回JSON格式实现方法详解

    2021-10-03 20:22:52
  • C#窗体传值代码方法

    2022-12-03 22:57:37
  • Android中的常用尺寸单位(dp、sp)快速入门教程

    2023-09-19 08:59:08
  • C++中的命名空间详细介绍

    2023-12-12 06:18:07
  • 两路归并的数组与链表的实现方法

    2021-10-28 04:32:15
  • SpringCloud Eureka服务治理之服务注册服务发现

    2021-12-27 15:07:16
  • javaweb前端向后端传值的几种方式总结(附代码)

    2022-04-28 09:21:29
  • springboot读取application.yaml文件数据的方法

    2023-09-06 05:29:24
  • spring定义和装配bean详解

    2023-08-23 00:33:18
  • JavaWeb项目Servlet无法访问问题解决

    2022-10-10 03:33:52
  • Android技巧一之启动屏+新功能左右导航逻辑

    2021-12-27 16:08:20
  • Android调用系统的发邮件功能的小例子

    2022-09-09 04:23:11
  • Android自定义View 实现水波纹动画引导效果

    2022-04-16 17:47:10
  • JVM完全解读之GC日志记录分析

    2022-09-22 12:43:08
  • 浅谈java中静态方法的重写问题详解

    2022-12-24 10:13:04
  • Java中基于Shiro,JWT实现微信小程序登录完整例子及实现过程

    2023-07-05 15:01:42
  • java实现打印正三角的方法

    2022-05-16 21:14:01
  • HashMap红黑树入门(实现一个简单的红黑树)

    2022-10-18 13:52:35
  • 用Newtonsoft将json串转为对象的方法(详解)

    2022-12-31 23:32:21
  • SpringBoot整合Activiti工作流框架的使用

    2022-03-02 12:32:44
  • asp之家 软件编程 m.aspxhome.com