目录
- 一、分层编译(TieredCompilation)
- 即时编译器(JIT)与解释器的区别
- 逃逸分析
- 二、方法内联(Inlining)
- 三、反射优化
一、分层编译(TieredCompilation)
JVM 将执行状态分成了 5 个层次:
0层:解释执行,用解释器将字节码翻译为机器码
1层:使用 C1 即时编译器编译执行(不带 profiling)
2层:使用 C1 即时编译器编译执行(带基本的profiling)
3层:使用 C1 即时编译器编译执行(带完全的profiling)
4层:使用 C2 即时编译器编译执行
profiling 是指在运行过程中收集一些程序执行状态的数据,例如【方法的调用次数】,【循环的 回边次数】等
即时编译器(JIT)与解释器的区别
解释器
● 将字节码解释为机器码,下次即使遇到相同的字节码,仍会执行重复的解释
● 是将字节码解释为针对所有平台都通用的机器码
即时编译器
● 将一些字节码编译为机器码,并存入 Code Cache,下次遇到相同的代码,直接执行,无需再编译
● 根据平台类型,生成平台特定的机器码
对于大部分的不常用的代码,我们无需耗费时间将其编译成机器码,而是采取解释执行的方式运行;另一方面,对于仅占据小部分的热点代码,我们则可以将其编译成机器码,以达到理想的运行速度。 执行效率上简单比较一下 Interpreter(解释器) < C1 < C2,总的目标是发现热点代码(hotspot名称的由 来),并优化这些热点代码
逃逸分析
逃逸分析===>分析 new Object()对象是否会在循环外被用到或被其他方法所引用,发现其为循环内的局部变量即采用优化手段。
首先分析例子(每次创建1000个对象耗费所需的时间)
运行后发现大约在第70次循环时速度突然变快,大约在159次时速度一下降低到了三位数(在运行期间Java虚拟机会对代码做一定的优化)
原因是什么呢?
—— JVM 将执行状态分成了 5 个层次
此种优化手段称之为逃逸分析,发现新建的对象是否逃逸。可以使用-XX:-DoEscapeAnalysis关闭逃逸分析
二、方法内联(Inlining)
内联函数
内联函数就是在程序编译时,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体来直接进行替换
private static int square(final int i){
return i*i;
}
如果发现square使热点方法,并且长度不太长时,会进行内联,所谓的内联就是把方法内代码拷贝、粘贴到调用者位置:
System.out.printf(9*9);
还能够进行常量折叠的优化
System.out.printf(81);
例子
大约在153次后花费时间为0,进行内联后将其看作常量
三、反射优化
public class Reflect1 {
public static void foo() {
System.out.println("foo...");
}
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method foo = Demo3.class.getMethod("foo");
for(int i = 0; i<=16; i++) {
// 执行反射调用(静态方法,无关联实例对象,因此参数为null)
foo.invoke(null);
}
}
}
结果:前16次调用性能相对较低,第17次调用开始性能会大大提升
foo.invoke 前面 0 ~ 15 次调用使用的是 MethodAccessor 的 NativeMethodAccessorImpl 实现
invoke方法源码
@CallerSensitive
public Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, obj, modifiers);
}
}
//MethodAccessor是一个接口,有3个实现类,其中有一个是抽象类
MethodAccessor ma = methodAccessor; // read volatile
if (ma == null) {
ma = acquireMethodAccessor();
}
return ma.invoke(obj, args);
}
会由DelegatingMehodAccessorImpl去调用NativeMethodAccessorImpl
NativeMethodAccessorImpl源码
class NativeMethodAccessorImpl extends MethodAccessorImpl {
private final Method method;
private DelegatingMethodAccessorImpl parent;
private int numInvocations;
NativeMethodAccessorImpl(Method var1) {
this.method = var1;
}
//每次进行反射调用,会让numInvocation与ReflectionFactory.inflationThreshold的值(15)进行比较,并使使得numInvocation的值加一
//如果numInvocation>ReflectionFactory.inflationThreshold,则会调用本地方法invoke0方法
public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
if (++this.numInvocations > ReflectionFactory.inflationThreshold() && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) {
MethodAccessorImpl var3 = (MethodAccessorImpl)(new MethodAccessorGenerator()).generateMethod(this.method.getDeclaringClass(), this.method.getName(), this.method.getParameterTypes(), this.method.getReturnType(), this.method.getExceptionTypes(), this.method.getModifiers());
this.parent.setDelegate(var3);
}
return invoke0(this.method, var1, var2);
}
void setParent(DelegatingMethodAccessorImpl var1) {
this.parent = var1;
}
private static native Object invoke0(Method var0, Object var1, Object[] var2);
}