JVM基础 -- JVM字节码执行过程
本文将通过是实例简单介绍
JVM字节码基于栈的执行过程
Stack Frame
- 一个方法
从调用到执行完成,对应着一个栈帧(Stack Frame)在虚拟机栈(VM Stack)里面从入栈到出栈的过程 - 在
编译成字节码期间,栈帧需要多大的局部变量表(Local Variable Table),多深的操作数栈(Operand Stack)都已经完全确定,并且写入到方法表的Code属性中 - 在
活动线程中,只有位于栈顶的栈帧才是有效的,称为当前栈帧,与这个栈帧关联的方法称为当前方法 - 局部变量表
- 用于存放
方法参数和方法内部定义的局部变量 - 方法表中的
locals属性记录了局部变量表的最大容量 - 局部变量表的存储单元为
32-bit的slot,boolean、byte、char、short、int、float等会占用一个slot,long和double会占用两个slot - 如果执行的是
实例方法,那么第0个slot默认存储this - 为了
节省栈帧空间,slot是可重用的
- 用于存放
- 操作数栈
- 方法表中的
stack属性记录了操作数栈的最大深度 - 操作数栈可以容纳任意的
Java数据类型,32-bit数据类型所占用的栈容量为1,64-bit数据类型所以占用的栈容量为2
- 方法表中的
代码
1 | package me.zhongmingmao.test; |
字节码
1 | # javap -v |
stack=2,这个在分析下面16个JVM字节码指令的运行过程后就能验证这是正确的,从Java源代码是无法直观的得出这个值locals=4,从Java源代码可以看出,calc()只定义了a、b、c三个局部变量,而calc()又是实例方法,局部变量表第1个slot默认会有记录this,因此能得出locals=4(在这里slot没有进行复用)- 在
JVM字节码中的LocalVariableTable属性,很清晰表述了局部变量表的布局,其中需要注意的是Start指的是局部变量生命周期开始的字节码偏移量,Length指的是作用范围覆盖的长度,而并非变量本身的长度 args_size=1,实例方法默认会传入this,因此args_size=1
执行过程
bipush 100
istore_1
iload_1
iload_2
iadd
iload_3
imul
ireturn
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.











