JVM学习笔记—JVM运行时内存之虚拟机栈
1.虚拟机栈
- Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,即生命周期和线程相同。
- Java虚拟机栈和线程同时创建,用于存储栈帧。
- 每个方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每一个方法从调用直到执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
2. 虚拟机栈—栈帧
- 栈帧(Stack Frame)是用于支持虚拟机进行方法调用和方法执行的数据结构。
- 栈帧存储了方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。
- 每一个方法从调用至执行完成的过程,都对应着一个栈帧在虚拟机栈里从入栈到出栈的过程。
- 结构如下图所示
3. 栈帧内部结构
4. 设置虚拟机栈的大小
- -Xss 为jvm启动的每个线程分配的内存大小,默认JDK1.4中是256K,JDK1.5+中是1M
-Xss1m -Xss1024k -Xss1048576
5. 虚拟机栈—局部变量表
- 局部变量表(Local Variable Table)是一组变量值存储空间,用于存放
方法参数
和方法内定义的局部变量
。 - 包括
8种基本数据类型(int,long,short ... )
、对象引用(reference类型)和returnAddress类型(指向一条字节码指令的地址,方法的返回地址)。 - 其中64位长度的long和double类型的数据会占用2个局部变量空间(Slot/槽),其余的数据类型只占用1个。
- 局部变量保存在哪,如下图所示:
- 栈帧里面有一部分区域用于保存局部变量的,叫做局部变量表
- 局部变量表也是一块一块的,里面有对应的索引
- 举个例子:
- 程序(图一)
- 字节码文件(图二)
- 行号表(图三)
- 局部变量表(图四)
- 程序(图一)
- 图三中Start PC 指的是字节码文件中的指令地址,Line Number指程序的行号
- 图四中 局部变量表有几个参数,Name那列中表示方法中的参数,args,x,y。Length表示有效长度范围,Index表示索引
6. 虚拟机栈—操作数栈
-
操作数栈(Operand Stack)也称作操作栈,是一个后入先出栈(LIFO)。
-
随着方法执行和字节码指令的执行,会从局部变量表或对象实例的字段中复制常量或变量写入到操作数栈,再随着计算的进行将栈中元素出栈到局部变量表或者返回给方法调用者,也就是出栈/入栈操作。
-
操作数栈就是不断加载程序中的值,然后把加载好的值放在局部变量表
-
举个例子:
- 程序计数器里面有一块区域,专门记录pc指令地址/偏移量
- 程序要是想要运行,首先是程序计数器先去找到pc指令地址/偏移量进行指针,指针首先放在0的位置上,之后0这个地址就会被程序计数器拿到,执行0对应的命令,声明一个变量1,将1放入操作数栈中
- 这时候指针指向偏移量是1的地方,程序计数器拿到1,执行存储1的命令,将1放入到局部变量表中
(声明和存储2同理)
- 当指针指向4的时候,程序计数器拿到4,执行命令加载1,是在局部变量表中加载这个1的值到操作数栈中,相当于一个复制的过程(加载2也是同理)
- 指针执行到6,程序计数器拿到6,在操作数栈中进行相加操作,得到3
- 指针执行到7,程序计数器拿到7,将3存储到局部变量表中
- 指针执行到8,程序计数器拿到8,将执行结果进行返回
-
总结
:这里面操作数栈完成的是加载好这些值,将加载好的值一个一个的放入局部变量表中,还有从局部变量表中加载出来一些值进行运算
8. 虚拟机栈—动态链接
- Java虚拟机栈中,每个栈帧都包含一个指向
运行时常量池
中该栈所属方法的符号引用,持有这个引用
的目的是为了支持方法调用过程中的动态链接(Dynamic Linking)。 动态链接的作用
:将符号引用转换成直接引用。- 动态链接,在动态链接中是没有对应的对象的,通过符号引用直接从常量池中拿到对应的值,直接拿来用。
- 举个例子:
9. 虚拟机栈—方法返回值地址
- 方法返回地址存放调用该方法的PC寄存器的值。
- 一个方法的结束,有两种方式:正常地执行完成,出现未处理的异常非正常的退出。
- 无论通过哪种方式退出,在方法退出后都返回到该方法被调用的位置。
- 方法正常退出时,调用者的PC计数器的值作为返回地址,即调用该方法的指令的下一条指令的地址。
- 而通过异常退出的,返回地址是要通过异常表来确定,栈帧中一般不会保存这部分信息。
- 无论方法是否正常完成,都需要返回到方法被调用的位置,程序才能继续进行。