Q: 运行时数据区的生命周期
- 跟随JVM的启动和退出
- 跟随线程的启动和退出
1. 栈帧
Q: 栈帧什么时候创建, 什么时候销毁
每次方法调用都会创建一个栈帧, 当方法调用结束之后(不管正常退出还是异常退出) 这个栈帧就会被销毁
Q: 1个线程中, 同时有几个栈帧在用
在一个线程中, 某一时刻只有1个栈帧是在用的(当前线程正在执行的方法)
Q: 线程中方法的嵌套调用, 会建立新的栈帧吗
会新建一个栈帧, 并且当前栈帧会指向这个新建的栈帧
Q: 方法调用的时候, 参数是怎么传递过去的, 类方法和实例方法有什么区别
参见 #1.1
Q: 栈帧里面存储什么数据
本地变量, 操作数栈, 运行时常量池的引用,
栈帧中存储什么数据, 使用什么结构, 占用空间, 怎么访问 ?
1.1 本地变量
存储了1个变量数组,称为本地变量, 放在一个数组中,数组大小在编译期便可确定, 使用下标访问(从0开始), 1个本地变量占用4个字节, 对于double
, long
则需要用2个连续的本地变量空间来存储
JVM使用本地变量来存储方法调用时的参数:
- 类方法调用时: 方法参数放在本地变量中,从0开始索引
- 实例方法调用时: 0处的数据为
this
的一个引用, 其他参数从1开始索引
1.2 操作数栈
JVM指令进行操作的时候,数据都是从操作数栈上获取的, 指令的结果也会回写到操作数栈, JVM提供了将数据从本地变量加载到操作数栈的指令(这些指令都是自带类型的), 嵌套方法中里面的方法执行完的结果放到外面的栈帧的操作数栈里面
1.3 动态链接
每个栈帧里都有1个对运行时常量池的引用, 为了当前方法能够实现动态绑定, 将class
文件中的通过符号引用的方法和变量通过动态链接找到具体的方法引用和具体的存储结构中的偏移
1.4 方法调用完成时栈帧的变化
正常退出时:
恢复调用者的本地变量,操作数栈,PC,并将返回结果放入调用者的操作数栈
异常退出时:
如果当前方法没有捕获异常,则不会有值返回给调用者
2. PC
寄存器
每个线程都有1个PC寄存器
- 如果当前方法不是native的, 则该寄存器存储的是正在执行的JVM指令的地址
- 如果当前方法是native的, 则该区域内容未定义
3. JVM栈
每个线程创建的时候都会创建一个JVM栈, 主要存储[栈帧](#1. 栈帧)
4. 堆
所有JVM中的线程,共用1个堆, 类的实例和数组都分配在这块
5. 方法区
所有JVM中的线程,共用1个方法区, JVM启动的时候创建该区域
主要存储各个类的:
- 运行时常量池
- 字段
- 方法数据
- 方法的代码
- 构造函数
- 用于初始化类/实例/接口的方法
5.1 运行时常量池
Q: 什么时候创建
JVM创建类/接口的时候
Q: 运行时常量池的个数
1个类/接口1个常量池
Q: 分配在JVM的哪块内存
分配在方法区
Q: 存储什么信息
编译期可知的数字型常量, 运行时可知的字段引用
6. native方法栈
为了调用native的方法需要一个native的方法栈
网友评论