周志明老师的《深入理解java虚拟机》
文章目录
Code 属性
之前说到方发表的时候,提到方法体被放在方法表的属性集合里面的 Code
属性中。
不是每一个方法表都必须有 Code
属性,比如 接口、抽象类方法 就不需要有 Code
属性。
Code
属性表结构如下:
类型 | 名称 | 数量 |
---|---|---|
u2 | attribute_name_index | 1 |
u4 | attribute_length | 1 |
u2 | max_stack | 1 |
u2 | max_locals | 1 |
u4 | code_length | 1 |
u1 | code | code_length |
u2 | exception_table_length | 1 |
exception_info | exception_table | exception_table_length |
u2 | attribute_count | 1 |
attribute_info | attributes | attributes_count |
-
attribute_name_index
索引指向常量池中的一个CONSTANT_Utf8_info
表 ,内容固定为属性的名字Code
。 -
attribute_length
属性值的长度,由于attribute_length
和attribute_name_index
一种占用6
(u2 和 u4
) 个字节,所以属性 值 的长度是整个属性 表 的长度减去6
; -
max_stack
操作数栈的最大深度。32
位的数据占1
个栈深度,64
位的数据占2
个栈深度。 -
max_locals
局部变量表所需的最大空间。单位是字宽Solt
,是JVM
为局部变量分配内存的最小单位。其中对于32
位数据类型占用1
个slot
,64
为位数据类型占用2
个Slot
。其中对象的引用,占一个slot
(32
位虚拟机中,64
位虚拟机可能不一样,看是否开启对象指针压缩)。局部变量包括方法中的定义的变量,方法中捕捉异常
catch
中的参数、还有方法本身的参数,尤其是是实例方法,要注意有一个默认的this
,this
对java
代码很重要,但是实现起来很精巧,在编译的时候,编译器将其对this
的访问,编译为对方法第一个参数的访问,然后在JVM
调用方法的时候,传入一个指向当前对象实例的局部变量 。因此,实例方法的局部变量表的第一个
Slot
槽位,都是this
。还有并不是申请多少个变量,然后计算下
slot
就是max_locals
的值,存在复用的情况,比如有的变量生命周期结束的早,那么它之前占用的空间,就会被重复使用,因此,这里是编译器根据作用域
算出max_locals
的值。 -
code_length
代表方法体编译以后的字节码指令长度,虽然是个u4
类型,占用4
个字节,虽然可以存储 232 -1 。但是虚拟机规范中有明确限制一个方法不能超过65535
条字节码指令。 一般不会有方法能这么长,为难编译器,但是JSP
有时候会将整个页面内容和输出信息放到一个方法里面,导致编译失败。 -
code
代表字节码指令,是个u1
类型,也就是每个指令用一个字节表示,单个字节最大可以 28 = 256 。所以一共有256
条指令,JVM
目前已经使用了200
多条指令。
博客停更一年,准备考研 ,see u again -2022年3月7日13:17:30