在Class文件中,Java方法里的方法体,也就是代表着一个Java源码程序中程序的部分存储在方法表集合的Code属性中。存储在Code属性中的是字节码,也就是编译后的程序。Java虚拟机的指令由两部分组成,首先是一个字节长度、代表某种含义的数字(即操作码),在操作码后面跟着零个或多个代表这个操作所需的参数(即操作数)。由于Java虚拟机采用的是面向操作数栈而不是寄存器的架构,所以大多数指令不包含操作数,只有一个操作码。
操作码的长度只有一个字节,这就限制了操作码的个数不超过256个。同时,Class文件格式放弃了编译后代码的操作数长度对齐,这就意味着虚拟机处理那些超过一个字节的数据时,不得不在运行时从字节中重建出具体数据的结构。比如,如果要将一个两个字节长的无符号整数使用两个无符号字节存储起来分别是byte1和byte2,那么就需要这样构造出原始的无符号整数:
(byte1<<8) | byte2
这样会在某种程度上导致执行字节码时损失一些性能。但这样做也有好处,那就是由于不需要对齐,省去了中间的填充与间隔符号;用一个字节来表示操作码,也是为了获得短小的编译代码。这样就尽可能的减少了编译后的代码的长度,非常适合网络传输。
如果不考虑异常处理的话,那么Java虚拟机的解释器可以使用下面的伪代码作为基本的执行模型来理解:
1 | do{ |
操作码,助记符表
1 | 字节码 助记符 指令含义 |