JVM 之 虚拟机字节码执行引擎及动态语言支持

运行时栈帧结构

栈帧:

局部变量表:
一组变量值存储空间。用于存放方法参数和方法内部定义的局部变量。 在Java程序被编译为Class文件时,就在方法的Code属性的max_locals数据项中 确定了方法所需要分配的最大局部变量表的容量。
单位:slot
存储数据类型和引用。
大小根据操作系统确定。32bit系统为32bit,64bit系统为64bit。存储数据类型时,如果小于32位使用一个slot;如果大于32位使用两个slot。

32位数据类型:
boolean,byte,char,short,int,float,refrence,returnAddress

64位数据类型:
long,double
复用:当一个变量的PC寄存器的值大于slot的作用域的时候,Slot是可以复用的。
		
代码优化:
局部变量没有初始值,声明时要赋值。		
对象使用完之后指向为null,方便垃圾回收。
	
操作数栈:
	运算的地方。
	一个以字长为单位的数组。通过压栈和出栈来访问。
	
动态链接
	静态链接:加载过程中间链接接转为直接链接
	动态链接:每次运行期间都会转化为直接链接
		
返回地址
	方法调用时记录调用方法地址,方法执行完毕之后跳回到所调方法位置。
	
附加信息
	虚拟机规范允许具体虚拟机添加一些规范中没有的信息到栈帧中。这些信息取决于虚拟机的实现。

方法调用

方法调用并不等于方法的执行,方法调用阶段的唯一任务就是确定被调用方法的版本。
  • 解析调用
    方法在编译的时候就确定了,方法的调用版本在运行之前不变的。(静态方法,构造器方法,私有方法,final方法)涉及到的指令:invokespecial,invokestatic。

  • 分派调用

    • 静态分派调用
      在编译器时期就确定方法的版本。如果存在函数重载,那么在调用是按照参数类型匹配最接近的方法。

    • 动态分派调用
      1.找到操作数栈顶的第一个元素所指向的对象的实际类型
      2.如果在实际类型中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果通过则直接返回这个方法的直接引用,查找过程结束,如果不通过,抛出异常。

动态语言支持

public class ScriptTest {

   public static void main(String[] args) throws ScriptException {

       ScriptEngineManager sem = new ScriptEngineManager();
       ScriptEngine se = sem.getEngineByName("JavaScript");
       Object obj = se.eval("function add(a,b){ return a+b;} add(2,3)");
       System.out.println(obj);
   }
}
发布了193 篇原创文章 · 获赞 13 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/u013919153/article/details/105393737