java 函数调用栈_Java Runtime Data Area & 函数调用栈 JVM Stack & 栈帧 ... - 简书

更多 Java 虚拟机方面的文章,请参见文集《Java 虚拟机》

运行时数据区 Runtime Data Area

JVM 执行 Java 程序时需要装载各种数据,比如类型信息(Class)、类型实例(Instance)、常量数据(Constant)、本地变量等。

不同的数据存放在不同的内存区中,这些数据内存区称作运行时数据区(Runtime Data Area)。

运行时数据区有这样几个重要区:

JVM Stack(简称 Stack 或者虚拟机栈、线程栈、栈等)

Frame(又称StackFrame/栈帧、方法栈等)

Heap(堆/GC堆,即垃圾收集的对象所在区)。

单个线程内共享的区:

PC Register 寄存器

JVM Stack 虚拟机栈

Native Method Stack 本地方法栈

所有线程共享的区:

Heap 堆

Method Area 方法区,其中包含 Runtime Constant Pool 常量池

8eee97251fd5

运行时数据区 Runtime Data Area

函数调用栈 JVM Stack

结构:

{JVM Stack [Frame][Frame][Frame]... }

Java 的函数调用栈就是 Java 虚拟机栈,它是线程私有的,与线程一同被创建,用于存储栈帧 Stack Frame,如下图所示。

8eee97251fd5

线程栈(VM Statck/Stack)包含的栈帧(Frame)

Throwable 的 getStackTrace() 可以返回当前线程的虚拟机栈信息,返回数组的第一个元素是栈顶元素,最后一个元素是栈底元素。

示例代码如下:

public class StackTrace_Test {

public void function1() {

function2();

}

public void function2() {

function3();

}

public void function3() {

Throwable ex = new Throwable();

StackTraceElement[] stackElements = ex.getStackTrace();

System.out.println("Stack Length: " + stackElements.length);

for (StackTraceElement stackTraceElement : stackElements) {

System.out.println("Method Name: "

+ stackTraceElement.getMethodName() + " Line Number: "

+ stackTraceElement.getLineNumber());

}

}

public static void main(String[] args) {

StackTrace_Test t = new StackTrace_Test();

t.function1();

}

}

输出如下:

Stack Length: 4

Method Name: function3 Line Number: 11

Method Name: function2 Line Number: 7

Method Name: function1 Line Number: 3

Method Name: main Line Number: 26

栈帧 Stack Frame

结构:

{Frame [ReturnValue] [LocalVariables[ ][ ][ ][ ]...] [OperandStack [ ][ ][ ]...] [ConstPoolRef] }

每次方法调用均会创建一个对应的 Frame,方法执行完毕或者异常终止,Frame 被销毁。

一个方法 A 调用另一个方法 B 时,A 的 Frame 停止,新的 Frame 被创建赋予 B,执行完毕后,把计算结果传递给 A,A 继续执行。

局部变量表 LocalVariables

局部变量表的大小在编译期就被确定,这些值并放在class文件中。

局部变量区被组织成一个以字长为单位、从 0 开始计数的数组。

字节码指令通过以 0 开始的索引来使用其中的数据。

类型为 int、float、refence(引用)和returnAdress(方法出口)的值在数组内只占据一项

类型为 byte、short、char 的值在存入数组时都先转换为 int 值,因此同样只占据一项

类型为 long 和 double 的值在数组中却占据了连续两项。

局部变量区包含了对应的 方法参数 和 局部变量!!!

Java代码 int a=0; int b=1; int c=2; 对应的局部变量表如下:

LocalVariableTable:

Start Length Slot Name Signature

2 12 0 a I

4 10 1 b I

6 8 2 c I

其中:

Start 变量偏移量。

Length 作用域范围长度。[ Start, Start + Length )就是该变量的作用域。

Slot 一个Slot能存储 32bit 的数据类型、引用、返回地址,long / dobule需要两个Slot。

操作数栈 OperandStack

操作数栈 OperandStack 的大小在编译期就被确定,这些值并放在class文件中。

Frame 被创建时,操作栈是空的。操作栈的每个项可以存放 JVM 的各种类型数据,包括 long / double。

操作栈有个栈深,long / double贡献两个栈深。

操作栈调用其它有返回结果的方法时,会把结果 push 到栈上。

当虚拟机调用一个方法时,它从对应的类的类型信息得到 局部变量表 LocalVariables 和 操作数栈 OperandStack 的大小,并据此分配栈帧内存,并压入 JVM Stack 中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值