在局部变量表中,可以使用插件jclasslib
来分析字节码,具体使用步骤如下:
1.打开idea
,安装插件
2.Slot
的理解
局部变量表以变量槽(slot) 为最小单位,这里不过多解释,可以参考虚拟机栈详解,
之所以要解释slot
,是因为我们往后学习的字节码指令,pc寄存器等都需要这方面的知识,话不多说,图中展示了不同的数据类型占据了不同数量的slot
,对应的参数也就发生变化,而java虚拟机执行编译好的代码就要从这些索引开始去访问局部变量
3.jclasslib
解析
随便写一个类
public class stackTest {
public static void main(String[] args) {
stackTest s = new stackTest();
s.method1();
}
void method1(){
System.out.println("method1 start......");
try {
method2();
} catch (Exception e){
e.printStackTrace();
}
System.out.println("method1 end......");
}
void method2(){
System.out.println("method2 start......");
method3();
System.out.println("method2 end......");
System.out.println(10 / 0);
}
void method3(){
System.out.println("method3 start......");
System.out.println("method3 end......");
}
}
编译后使用jclasslib
显示详细信息
我们会来到这样一个页面:
接下来我们一一解释这里面的内容
3.1code
属性
然后点击Bytecode
3.2LineNumTable
和LocalVariableTable
介绍完code
,再继续介绍下面两个内容,这两个内容要结合在一起理解:
首先点击第一个LineNumTable
然后点击第二个LocalVariableTable
注意:这两个内容的startPC
都一样
注意:在编译好了的字节码指令中,每个方法的参数索引都是从0
开始的,在加载这个类的时候,java虚拟机会自动的创建一个<init>
构造方法来初始化这个类,当其他的方法都是基于这个方法产生或者实例方法(非静态方法
),在其他方法(栈帧)中都会用自己本身对象this
来代替参数索引0
说明了上述的注意点,其实很多我们之前遇到的问题都可以得到介绍了:
有这样一个类:
public class stackTest {
static int count = 1;
public static void main(String[] args) {
stackTest s = new stackTest();
s.method1();
System.out.println(this.count)//这里会报错,因为this变量不存在main方法局部变量表中
}
void method1(){
this.count++;//这里写不写count都一样,因为在局部变量表中已经存在了this变量,在字节码指令索引为0处
}
我们可以来看一下结果论证一下
需要注意的是:slot是可以复用的,当一个局部变量过了其作用域,那么在其作用域之后申明的新的局部变量就很可能会复用过期局部变量的槽位,从而达到节省资源的目的