栈与栈帧

Java Virtual Machine Stacks (Java 虚拟机栈)

  • JVM 中由堆、栈、方法区所组成,其中栈内存是给线程使用,
  • 每个线程启动后,虚拟机就会为其分配一块栈内存。
  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

具体示例如下 :

package cn.knightzz.example.e2.source;

public class TestFrame {


    public static void method1(int n) {

        Object m = method2(n + 1);
        System.out.println("m = " + m);

    }

    public static Object method2(Object n) {
        return n;
    }

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

当我们运行到主线程method1(10) 时, 可以看到只有主线程在活动

img

而当我运行到method2(n+1) 位置时 当前的活动栈帧对应着 method1

img

继续运行直到运行到 method2时可以看到此时有三个栈帧, 活动栈帧是 method2, 所以

  • 每个栈由多个栈帧(Frame)组成,对应着每次方法调用时所占用的内存
  • 每个线程只能有一个活动栈帧,对应着当前正在执行的那个方法

img

栈帧图解

代码示例

package cn.knightzz.example.e2.source;

/**
 * @author 王天赐
 * @title: TestFrame
 * @projectName hm-juc-codes
 * @description: 线程的栈帧
 * @website <a href="http://knightzz.cn/">http://knightzz.cn/</a>
 * @github <a href="https://github.com/knightzz1998">https://github.com/knightzz1998</a>
 * @create: 2022-06-15 22:18
 */
public class TestFrame {


    public static void method1(int n) {

        Object m = method2(n + 1);
        System.out.println("m = " + m);

    }

    public static Object method2(Object n) {
        return n;
    }

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

初始状态如下 :

  • 所有的代码加载进方法区, JVM虚拟机为主程序分配栈内存

img

执行主方法, 创建 main栈帧

img

局部变量表 :

  • 存储局部变量以及方法参数, 对于main函数来说, 局部变量表存储的就是 args
  • args 存储的是执行程序的命令信息 : java -jar -Xmx2G 后面的参数信息

继续向下执行, 执行到 method1 方法内是 , 此时注意 :

  • 程序计数器里记录了此时程序的位置 : method1(10), 随着继续向下执行, 程序计数器会记录执行的每一行代码
  • 返回地址指向方法区里 main 函数位置的 method1(10) 位置
  • 局部变量存储了 nm两个变量, 一个是方法输入参数, 一个是对象
  • 注意 : 对象是存储在堆中的

img

当我们继续向下执行时, 执行到 method2 :

  • 返回地址指向 method1 中调用 method2 的位置

img

当最后一个方法 method2 执行结束后, 会根据返回地址逐步返回