字节码执行引擎
栈帧:
局部变量表:编译时确定大小,slot(一般32bit,可存放reference用于找到对象和类型数据)
连续2slot(64bit,long,double,可以非原子操作,反正这是线程私有的)
实例方法this,参数,局部变量
static方法参数,局部变量
slot可重用,局部变量必须先赋值后使用
操作数栈:编译时确定大小,基于栈(即操作栈)的解释执行引擎
动态连接:指向方法的引用(运行时常量池(含字面量,符号引用(对类,Field,Method等的引用),直接引用))
返回地址:正常退出(可带返回值),异常退出,返回值压入调用者的操作数栈,pc后移。
方法调用:指确定方法版本
解析调用:编译期确定好,类加载时符号引用转直接引用
invokestatic 静态方法,非虚
invokespecial init,private,父类方法,非虚
invokevirtual final(非虚),其他虚
invokeinterface 虚
invokedynamic
分派(dispatch)调用
静态分派:编译期,根据(调用者静态类型,参数静态类型,参数个数,多分派)确定方法重载版本
静态分派不确定性,'a’作为参数,可以依次调用char,int,long,Character,Serializable,Object,char…的 重载版本
动态分派:运行期,根据 调用者实际类型(单分派)确定方法重写版本
找到实际类型后不断向上找,并需进行访问权限校验
实现:虚方法表(每个类都有虚方法表,包含所有方法的地址(Object方法也在内),重写方法指向自己类型数据(方法实现的入口地址),未重写指向父类类型数据)
一个static方法调用,可能先静态分派调用确定重载版本,再解析调用转为直接引用
基于栈的指令集,多为零地址指令,依赖操作数栈工作
可移植,不受硬件(寄存器)约束,虚拟机可将hot的数据放于寄存器,代码紧凑(如一个byte对应一个指令)
但是执行慢:
1 指令数量多,大量出入栈
2 栈在内存中,频繁访存也慢
1+1 (iconst_1 iconst_1 iadd istore_0 ) ( mov eax, 1 add eax, 1)
上图显示执行偏移为2的指令执行情况。