JVM之java栈

JVM之java栈

简介

与程序计数器一样,Java虚拟机栈(JavaVirtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

每当启动一个新线程时,Java虚拟机都会为它分配一个Java栈。Java栈以帧为单位保存线程的运行状态。虚拟机只会直接对Java栈执行两种操作:以帧为单位的压栈和出栈。

某个线程正在执行的方法被称为该线程的当前方法。当前方法使用的栈帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。在线程执行一个方法时,它会跟踪当前类和当前常量池。此外,当虚拟机遇到栈内操作指令时,它对当前帧内数据执行操作。

每当线程调用一个Java方法时,虚拟机都会在该线程的Java栈中压入一个新帧。而这个新帧自然就成了当前帧。在执行这个方法时,它使用这个帧来存储参数、局部变量、中间运算结果等数据。

Java方法可以以两种方式完成。一种通过return正常返回;一种通过抛异常返回。不管怎么返回,虚拟机都会将当前帧弹出栈并释放,这样上一个方法的帧就成了当前帧。

Java栈上的所有数据都是此线程私有的。任何线程都不能访问另一个线程的栈数据,因此我们不需要考虑多线程情况下栈数据的访问同步问题。当一个线程调用一个方法时,方法的局部变量保存在调用线程Java栈的帧中。只有一个线程能总是访问那些局部变量,即调用方法的线程。

栈帧

栈帧由三部分组成:局部变量区帧数据区操作数栈。局部变量区和操作数栈的大小要视对应的方法而定,它们是按字长计算的。编译器在编译时就确定了这些值并放在class文件中。而帧数据区的大小依赖于具体的实现。

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

局部变量区:

Java栈帧的局部变量区被组织为一个以字长为单位、从0开始计数的数组。字节码指令通过从0开始的索引来使用其中的数据。如:

Class Example{

Public static int runClassMethod(int i,long l,float f,double d,Object o,byte b) {                                                 

Return 0;

}

Public int runInstanceMethod(char c,double d,short s,boolean b) {

Return 0;

}

}

 

 

runClassMethod的局部变量区:

索引                                 

类型                                       

参数                                   

0

int

Int i

1

long

Long l

2

 

 

3

Float

Float f

4

double

Double d

6

reference

Object o

7

int

Byte b

runInstanceMethod的局部变量区:

索引                                  

类型                                      

参数                                   

0

Reference

Hidden this

1

int

Char c

2

double

d

3

 

 

4

int

Short s

5

int

Boolean b

注意上面图标的几个事项:

1. 类型为int、float、reference、returnAddress的值在数组中只占据一项。

2. 类型为byte、short、char的值在存入数组前都将被转换为int值,他们在栈帧中被当做int来处理,只有当它被存回堆或方法区时,才会转换回原来的类型。

3. Long和double的值在数组中占据连续的两项。

4. runInstanceMethod方法的第一项是一个隐含的reference,代表this,对于任何一个实例方法都是隐含加入的,而由于runClassMethod方法是类方法,所以数组中没有此项。

5. 注意输入参数Object o被标记为reference,在Java中,所有的对象都是按引用传递,并且都存储在堆中,永远都不会在局部变量区或操作数栈中发现对象的拷贝,只会有对象的引用。

操作数栈

和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组,但是和前者不同的是,他不是通过索引来访问的,而是通过标准的栈操作——压栈和出栈来访问的。

实例:

Iload_0  //把int类型的索引为0的局部变量区数据压入操作数栈

Iload_1   //把int类型的索引为1的局部变量区数据压入操作数栈

Iadd   //操作数栈数据相加

Istore_2 //把操作数栈的数据出栈,存储到局部变量区索引为2的位置

下边是具体快照:

 

开始之前

Iload_0

Iload_1

iadd

Istore_2

局部变量区

0

100

0

100

0

100

0

100

0

100

1

98

1

98

1

98

1

98

1

98

2

 

2

 

2

 

2

 

2

198

帧数据区

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

...

操作数栈

 

 

 

100

 

100

 

198

 

 

 

 

 

 

 

98

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值