1、什么是方法内联?
方法内联:指的是在即时编译过程中遇到方法调用时,直接编译目标方法的方法体,并替换原方法调用。
- 方法内联属于即时编译期的优化技术;
- 即时编译的过程是字节码被解析成IR图,优化IR图,再由优化过的IR图生成机器码的过程;
- 解析指的是即时编译器对字节码做的动作,是字节码到IR图的转换;
2、什么是逃逸分析?
逃逸分析:Escape Analysis简单来讲就是,Java Hotspot 虚拟机可以分析新创建对象的使用范围,并决定是否在 Java 堆上分配内存的一项技术。 逃逸分析的 JVM 参数如下:jdk6之后默认开启逃逸分析 开启逃逸分析:-XX:+DoEscapeAnalysis 关闭逃逸分析:-XX:-DoEscapeAnalysis 显示分析结果:-XX:+PrintEscapeAnalysis
- 锁消除
- 标量替换
- 栈上分配
3、反射为什么慢?
- fan射的实现如下代码
// v0 版本
import java.lang.reflect.Method;
public class Test {
public static void target(int i) {
new Exception("#" + i).printStackTrace();
}
public static void main(String[] args) throws Exception {
Class<?> klass = Class.forName("Test");
Method method = klass.getMethod("target", int.class);
method.invoke(null, 0);
}
}
##Method的invoke方法
public final class Method extends Executable {
...
public Object invoke(Object obj, Object... args) throws ... {
... // 权限检查
MethodAccessor ma = methodAccessor;
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
}
反射的实现过程,分别调用了Class.forName、Class.getMethod、Method.invoke方法
- Class.forName:会调用本地方法,可想而知个操作非常费时。
- Class.getMethod:则会遍历该类的公有方法。如果没有匹配到,它还将遍历父类的公有方法,也挺耗时。
- Method.invoke:这个方法的实现,它实际上委派给MethodAccessor来处理。MethodAccessor是一个接口,它有两个已有的具体实现。 一个通过本地方法来实现反射调用,另一个则使用了委派模式。为了方便记忆,我便用“本地实现”和“委派实现”来指代这两者。动态实现和本地实现相比,其运行效率要快上20倍。这是因为动态实现无需经过 Java 到 C++ 再到 Java 的切换,但由于生成字节码十分耗时,仅调用一次的话,反而是本地实现要快上3到4倍。考虑到许多反射调用仅会执行一次,Java 虚拟机设置了一个阈值 15(可以通过 -Dsun.reflect.inflationThreshold= 来调整),当某个反射调用的调用次数在 15 之下时,采用本地实现;当达到 15 时,便开始动态生成字节码,并将委派实现的委派对象切换至动态实现,这个过程我们称之为 Inflation(方法内联)。
- Method.invoke方法的反射调用会带来不少性能开销,原因主要有三个:变长参数方法导致的 Object 数组,基本类型的自动装箱、拆箱,还有最重要的方法内联。
JVM方法调用的指令
- invokeinterface:用以调用接口方法,在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。(Invoke interface method)
- invokevirtual:指令用于调用对象的实例方法,根据对象的实际类型进行分派(Invoke instance method; dispatch based on class)
- invokestatic:用以调用类方法(Invoke a class (static) method )
- invokespecial:指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法、私有方法和父类方法。(Invoke instance method; special handling for superclass, private, and instance initialization method invocations )
- invokedynamic:JDK1.7新加入的一个虚拟机指令,相比于之前的四条指令,他们的分派逻辑都是固化在JVM内部,而invokedynamic则用于处理新的方法分派:它允许应用级别的代码来确定执行哪一个方法调用,只有在调用要执行的时候,才会进行这种判断,从而达到动态语言的支持。(Invoke dynamic method)