介绍
每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈针
虚拟机栈是线程私有的
生命周期
生命周期和线程一致
作用
主管Java程序的运行,他保存方法的局部变量(8种基本数据类型,对象的引用地址),部分结果、并参与方法的调用和返回
特点
栈是一种高效的分配存储方式
JVM直接对栈的操作只有两种
方法执行 入栈
方法执行结束 出栈
栈不存在垃圾回收问题
但是存在OOM
设置栈内存大小
使用-Xss来设置栈内存大小
-Xss 1024k
栈的存储单位
栈中存储什么
每个线程都有自己的栈,占中的数据都是以栈帧的格式存在
在这个线程上正在执行的每个方法都各自对应一个栈帧
栈帧的一个内存区块,是一个数据集,维系着方法执行过程中的各种数据信息
栈的运行原理
不同线程中所包含的栈帧是不允许存在相互引用的
如果当前方法调用了其他方法,方法返回之际,当前栈帧会传回此方法的执行结果给当前一个栈针,并且虚拟机会丢弃当前栈帧,使得前一个栈帧重新成为当前栈帧
Java方法有两种返回函数的方式,一种是正常的函数返回,使用return指令;另一种是抛出异常。不管使用哪种方式,都会导致栈帧被弹出
局部变量表
局部变量表也成为局部变量数组或本地变量表
定义为一个数字数组,主要用于存储方法参数和定义在方法体内的局部变量,这些数据类型包括各种基本数据类型,对象引用,以及returnAddress类型
由于局部变量表是建立在线程的栈上,是线程的私有数据,因此不存在数据安全问题
局部变量表所需的容量大小是在编译期确定下来的,并保存在方法Code属性的maxmun local variables数据项中。 在方法运行期间是不会改变局部变量表的大小的。
方法嵌套调用的次数由栈的大小决定。 栈越大,方法嵌套调用次数越多
局部变量表中的变量只在当前方法调用中有效。 当方法调用结束后,随着方法栈帧的销毁,局部变量表也会随之销毁。
Slot的理解
参数值的存放总是在局部变量数组的index0开始,到数组长度-1的索引结束
局部变量表,最基本的存储单元是slot
局部变量表中存放编译期可知的各种基本数据类型,引用类型,returnAddress类型的变量
局部变量表中,32位以内的类型只占用一个slot, 64位的类型占用两个slot
Byte,short,char 在存储前被转换为int,boolean 也被转换int, 0表示false,非0表示true
long和double则占据两个slot
操作数栈
操作数栈,在方法执行过程中,根据字节码,往栈中写入数据或提取数据
主要用于保存计算过程的中间结果,同时作为计算过程中变量临时的存储空间
操作数栈就是jvm执行引擎的一个工作区,当一个方法刚开始执行的时候,一个新的栈帧也会随之被创建出来,这个方法的操作数栈是空的
每个操作数栈都会拥有一个明确的栈深度用也存储数值,其所需的最大深度在编译期就定义好了,保存在方法的code属性中,为max_stack的值
栈中的任何一个元素都可以是任意的Java数据类型
32bit的类型占用一个栈单位深度
64bit的类型占用两个栈单位深度
操作数栈并非访问索引的方法来进行数据访问的,而是只能通过标准的入栈和出栈操作来完成一次数据访问
如果被调用的方法带用返回值的话,其返回值将会被压入当期栈的操作数栈中。
方法的调用
静态链接:
动态链接:
java语言中方法重写的本质
- 找到操作数栈顶的第一个元素所执行的对象的实际类型,记做C
- 如果在过程结束;如果不通类型C中找到与常量中描述符合简单名称都符合的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用
- 否则,按照继承关系从下往上一次对C的各个父类进行第2步的搜索和验证过程
- 如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError异常。