纯编译型语言:在程序启动时,将编写好的源码全部编译为所处平台的机械码指令。
特点:执行性能最佳,启动时间较长,移植性差,不同平台需要重新发包。
纯解释型语言:在程序运行过程中,需要执行某处代码时,再将该代码解释为平台对应的机械码指令,然后交由计算机执行。
特点:启动速度快,执行性能较差,移植性较好。
Java虚拟机的执行引擎子系统中包含两种执行器,分别为解释器和即时编译器。当执行引擎获取到由javac编译后的.class
字节码文件后,在运行时是通过解释器(Interpreter)转换成最终的机械码执行。另外为了提升效率,JVM加入了一种名为 JIT即时编译 的技术,即时编译器的目的是为了避免一些经常执行的代码被解释执行,JIT会将整个函数编译为平台本地的机械码,从而在很大程度上提升了执行的效率。
1.执行子引擎
1.Java的执行引擎子系统的主要任务是将字节码指令解释/编译成对应平台上的本地机器指令,简单来说,JVM执行引擎是充当Java虚拟机与操作系统平台之间的“翻译官”的角色。
2.即时编译器的优化(c1,c2)
C2编译器则主要是追求编译后的执行性能,属于激进派,C2编译器建立在C1编译器的基础优化之上,除开使用了C1中的优化手段之外,还有几种基于逃逸分析的激进优化手段:标量替换、栈上分配以及同步消除等。
一、同步省略。如果一个对象被发现只能从一个线程被访问到,那么对于这个对象的操作可以不考虑同步。
二、将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会逃逸,对象可能是栈分配的候选,而不是堆分配。
三、分离对象或标量替换。有的对象可能不需要作为一个连续的内存结构存在也可以被访问到,那么对象的部分(或全部)可以不存储在内存,而是存储在CPU寄存器中。
3.分派调用
多态性在运行时到底是如何找到具体方法的,如重写和重载方法到底在运行时是如何确定具体调用那个方法的呢?也就是通过分派技术进行调用的。
1.静态、私有、构造、父类、final方法都符合调用条件,所以这些方法在类加载阶段就会把符号引用替换成直接引用。因为这些方法是一个静态的过程,在编译期间就能完全确定版本,无需将这些工作延迟到运行期间再去处理,而这类调用方式就被称为静态分派。但对于公开实例方法、非私有成员方法这些就无法在编译期确定版本,所以这些方法的调用方式被称为动态分派。同时根据方法的宗量数也可分为单分派和多分派。
2.静态分派
编译期可以确定方法的版本,类加载阶段可以通过解析阶段完成版本判定
静态分派的典型体现是方法重载(Overload),重载方法的特性是方法签名不同(方法名相同、参数列表不同。
2.动态分派
动态分派是指在编译期无法通过静态类型判定出方法版本,需要在运行期间由虚拟机来判定方法调用的具体版本的方式。动态分派的典型体现是方法重写(Override),重写的概念是方法签名相同(方法名相同、参数列表相同)
过程:找到操作数栈顶部的第一个元素,也就是指向变量user
的实际类型,找到了将符号引用改为直接引用,没有继续自下向上的方式查找VipUser
父类的方法表
这种在运行期根据实际类型确定方法执行版本的分派过程称为动态分派