一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
什么是栈和栈帧
每个线程在创建时都会创建一个虚拟机栈,在线程内每次调用的方法就对应一个栈帧,是线程私有的。生命周期和线程一致。
栈帧存储结构
1.局部变量表 Local Variables
2.操作数栈 Operand Stack 或 表达式栈
3.动态连接 Dynamic Linking 或 指向运行时常量池的方法引用
4.方法返回地址 Return Address 或 方法正常退出或异常退出的定义
5.其他附加信息
其中方法返回地址,动态链接,附加信息总的也叫帧数据区。
1.局部变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法内部的局部变量。包括基本数据类型,对象的引用,以及returnAdress类型。
特点
1.局部变量表所需容量大小是在编译期确定下来的,并保存在方法的code属性的maximum local variables数据项中。在方法运行期间不会改变局部变量表的大小。
2.局部变量表只在当前方法调用中有效。在方法执行时,虚拟机通过使用局部变量表完成参数值到参数列表的传递过程,当方法调用结束后,随着方法栈帧的销毁,局部变量也会随之销毁。
3.局部变量表最基本的单位是slot
4.当一个方法被调用时,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个slot上
5.非静态方法,该方法的当前对象this将会被放到index为0处
6.局部变量表中的槽可以重用,如果一个局部变量过了其作用域,那么后面声明的局部变量就可能会复用已经过期的局部变量的槽位。从而达到节省资源的目的。
7.局部变量表中的变量也是重要的垃圾回收根节点,只要是被局部变量表直接或间接引用的对象都不会被回收
槽 slot
1.在局部变量表里,32位之内的类型只占用一个slot,64位的类型(long,double)占用两个slot。
2.当一个方法被调用时,它的方法参数和方法体内部定义的局部变量将会按照顺序被复制到局部变量表中的每一个slot上
成员变量和局部变量对比
成员变量:
类变量:在类加载器加载类阶段赋值
实例变量:在创建对象阶段赋值
局部变量:必须人为进行赋值。
2.操作数栈 Operand Stack(表达式栈)
使用数组实现的栈
在方法执行的过程当中,根据字节码指令,往栈中写入数据或提取数据。
特性
主要用于保存计算过程的中间结果,同时作为计算过程中变量的临时存储内存空间。
操作数站就是jvm调用的一个工作区,随着方法的调用,栈帧的创建而被创建,刚创建是栈中数据为空。
操作数栈的深度在编译期间就被确定好了
3.动态链接 Dynamic Linking
每个栈帧内部都包含一个指向运行时常量池中该栈帧所属方法的引用,包含这个引用的目的就是为了当前方法的代码能够实现动态链接。比如invokeynamic (解释:在java源文件被编译为字节码文件时,所有变量和方法引用都以符号引用的方式保存到class文件的常量池中。一个方法调用了另外的其他方法时,就是通过方法区的常量池中指向方法的符号来表示,动态链接的作用就是将这些指向方法的符号转化为调用方法的直接引用。)