注:主要参考自《分布式java应用:基础与实践》《深入理解Java虚拟机(第二版)》

 

1、两种执行方式:

  • 解释执行(运行期解释字节码并执行)
    • 强制使用该模式:-Xint
  • 编译为机器码执行(将字节码编译为机器码并执行,这个编译过程发生在运行期,称为JIT编译)
    • 强制使用该模式:-Xcomp,下面是两种编译模式
    • client(即C1):只做少量性能开销比高的优化,占用内存少,适用于桌面程序。
    • server(即C2):进行了大量优化,占用内存多,适用于服务端程序。会收集大量的运行时信息。

注意:

  • 32为机器默认选择C1,可在启动时添加-client-server来指定,64位机器若CPU>2且物理内存>2G则默认为C2,否则为C1
  • Hotspot JVM执行代码的机制:对在执行过程中执行频率高的代码进行编译,对执行频率不高的代码继续解释执行

查看当前机器默认是client模式还是server模式,使用:"java -version"命令,如下

第六章 字节码执行方式--解释执行和JIT

其中,mixed mode表示"解释执行+编译执行"的混合模式

2、解释执行

查看 第三章 类文件结构与javap的使用 中的inc()方法的执行

或者查看《深入了解java虚拟机(第二版)》P272-P275

 

3、编译执行

  • 编译的对象
    • 方法
    • 方法中的循环体
      • OSR编译:编译整段代码,但是只有循环体部分会执行机器码,其他部分还是解释执行
  • 触发条件(执行频率大于多少)
    • 方法调用计数器:方法被调用的次数
      • client:1500  server:10000 
      • 该阈值可通过-XX:CompileThreshold来指定
      • 这里"方法调用的次数"是指一段时间(半衰周期)内的调用次数,如果半衰周期内,该次数没有达到阈值,则该次数减半
        • -XX:-UseCounterDecay 关闭上述机制,即半衰周期的无穷大
        • -XX:CounterHalfLifeTime 半衰周期
    • 回边计数器:循环体内循环代码的执行次数(即for中代码的循环的次数
      • client:13995  server:10700
      • 该阈值可通过-XX:OnStackReplacePercent(注意该OSRP只是一个计算回边计数阈值的中间值),回边计数阈值
        • client:CompileThreshold*OSRP/100
        • server:CompileThreshold*(OSRP-InterPreterProfilePercentage)/100
        • -XX:OnStackReplacePercent:140  InterPreterProfilePercentage:33
  • 方法编译执行
    • 解释器调用方法时,检查是否有已经存在的编译版本,如果有,执行机器码,如果没有,方法调用计数器+1,然后判断方法调用计数器是否超过阈值,若超过,进行编译,后台线程进行编译,前台线程继续解释执行(即不会阻塞),直到下一次调用方法时,如果编译好了,就直接执行机器码,如果没编译好,就解释执行。
  • 循环体编译执行
    • 解释器执行到循环体时,检查是否有已经存在的编译版本,如果有,执行机器码,如果没有,回边计数器+1,然后判断回边计数器是否超过阈值,若超过,进行编译,后台线程进行编译,前台线程继续解释执行(即不会阻塞),直到下一次执行到循环体时,如果编译好了,就直接执行机器码,如果没编译好,就解释执行。

 

4、C1优化

说明:关于全部的优化技术列表,查看《深入理解java虚拟机(第二版)》P346-P347

只做少量性能开销比高的优化,占用内存少,主要的优化包括:

  • 方法内联
  • 冗余消除
  • 复写传播
  • 消除无用代码
  • 类型继承关系分析(CHA,辅助)
  • 去虚拟化

4.1、方法内联、冗余消除、复写传播、消除无用代码

4.1.1、方法内联

方法内联含义:假设方法A调用了方法B,把B的指令直接植入到A中。

    static class B{
        int value;
        final int get() {
            return value;
        }
    }
    
    public void foo() {
        y = b.get();
        //do something
        z = b.get();
        sum = y + z;
    }
View Code

相关文章: