Jvm运行期优化

关于Jvm运行期优化 Fate

编译器&解释器

解释器(Interpreter):故名思议,在机器读取.class文件时,通过解释器将字节码转化为机器码,交给机器执行,特点是读一句执行一句
即时编译器:在运行时期把字节码编译成原生机器码的技术,一句一句翻译源代码,但是会将翻译过的代码缓存起来以降低性能耗损(热点代码)
当前大部分主流虚拟机都是同时包含解释器与编译器 如图

  • 热点代码 热点代码包括:被多次调用的方法;被多次执行的循环体
    判断是否热点代码的方式有两种方式:基于采样/基于计数器
    方法调用计数器: 如图 回边计数器:
    统计一个方法中循环体代码执行的次数

编译优化技术

  • 公共子表达式消除 如果一个表达式E已经被计算过,切E中变量没有变化,那么E就变为公共子表达式,以后就没有必要对它进行计算,直接使用计算过的结果替换E
    int d = (c*b)*12 + a + (a+b*c)
    进入虚拟机即时编译后
    int d = E*12 + a + (a + E) -> int d = E*13 + a*2
    
  • 数组边界检查消除

  • 方法内联 简单来说就是将目标代码赋值到发起调用的方法中,避免真实的方法调用
    在编译器内联时,如果时非虚方法,直接内联就可以;如果时虚方法,则会查询在当前程序是否有多个版本可选,如果只有一个版本,那也可以内联(激进优化);

  • 逃逸分析 分析对象动态作用于,当对象在方法中被定义,可能被外部方法引用; 作为调用参数传递到其他方法,就是方法逃逸;若被外部县城访问,称为线程逃逸;
    如果能证明一个对象不会逃逸,则可能会有以下优化
    1.栈上分配
    堆中的对象可以线程共享,垃圾回收时对于堆上的对象需要耗费时间;所以如果能确定一个对象不会逃逸,那么可以让对象在栈分配内存
    2.同步消除
    如果确定一个对象不会线程逃逸,那么可以消除变量的同步措施
    3.标量替换
    如果一个数据已经无法分解为更小的数据,例如int,long等,就可以称为标量,如果可以继续分解,就称为聚合量,例如java的对象;如果将java对象拆散,将其用到的成员变量回复原始类型范文就叫标量替换。如果对象不会被外部访问,且对象可以被拆散,那么程序执行时可能不创建这个对象,而直接创建它的若干被方法使用到的成员变量代替
    对象拆散?