即时编译

即时编译:

(先说一下学习jvm的感想:即时编译器在程序的执行效率做了大量的优化,背后涉及了编译原理以及大量的优化算法,每种算法的背后都是由神仙写的一篇篇优秀的论文的实现。我们的工作更像是应用工程师,站在这些神仙们的肩膀上开发功能,在实际应用中并不会用到这些编译和算法,因此只是做了一些肤浅的了解,知道了有这么个东西。我们也不应该做深入的了解,性价比也是不高,平时用不到,很快就忘了。)


   1. 即时编译:
        反复执行的热点代码会被即时编译成机器码,直接运行在底层硬件之上,提升了程序的执行效率。
   2. 分层编译:
        执行时间长,对峰值性能有要求的程序,采用c2,(服务端即时编译)
        执行时间短,对启动性能有要求的程序,采用c1,(客户端即时编译)
   3. 即时编译的触发:
        当方法的调用次数以及循环回边的执行次数达到一定的条件之后,就会触发即时编译。
    4.osr编译,
        除了以方法为单位进行即时编译,还存在着以循环为单位的即时编译(OSR)。循坏回边计数器就是触发这种类型的编译。
        OSR可以在程序执行过程中,动态地替换掉java方法栈帧,从而使得程序能够在非方法入口处进行解释执行和编译后的代码之间的切换。
   5. Profiling  [ˈprəʊfaɪlɪŋ]
        5.1在分层编译的0,2,3三层中都会进行profiling,收集能够反映程序运行状态的数据。比如有:
            方法的调用次数,
            循环回边的次数。当这些次数达到一定的条件之后,会触发即时编译。
            此外,0层和3层,还会收集用于4层c2编译的数据,分支profiling和类型profiling。0层只有在等待c1编译的方法太多,才会进行profiling,否则是在c1代码中进行profiling(java虚拟机认为该方法可能被c2编译)
                分支profiling:跳转次数,不跳转次数
                类型prolifing:非私有实例方法调用指令,强转类型,instanceof指令,数组存储指令
        
       5.2 分支Profile优化
            即时编译器可以将从未执行过的分支剪掉,以避免编译这些很有可能用不到的代码,从而节省编译时间以及部署代码所有消耗的内存空间。
            还可以计算每条程序执行路径的概率,以便某些编译器优化优先处理概率较高的路径。
        
        5.3类型profile优化
            instanceof 改为判断输入的类型是否为profiling的类型,是的话,执行类似分支的优化。不是的话,去优化
            方法调用类型,对方法的条件去虚化内联。
            
        5.4去优化
            分支profile和类型profile是基于假设做的优化,从而精简控制流以及数据流。当假设失败的时候会执行去优化。
            
            去优化。从执行即时编译生成的机器码切换回解释执行。
                在生成的机器码中,即时编译器在假设失败的地方插入一条call指令,调用jvm去优化的方法,去优化方法更改栈上的返回地址,并不再返回即时编译器生成的机器码中。
                即时编译器在编译过程中机器码和字节码之间的映射关系。当根据映射关系创建好对应的解释执行栈后,jvm采用osr技术,动态替换栈上的内容,并在目标字节码出开始解释执行。
                
                即时编译器还可以根据产生去优化的原因来决定是否保留这一份机器吗,以及何时重新编译对应的java方法。

6.即时编译器的中间表达式形成
        编译原理课中,编译器分为前端和后端,前端会对所输入的程序进行词法分析,语法分析,语义分析,然后生成中间表达形式,也就是IR,后端会进行IR的优化,然后生成目标代码。
            
        即时编译器将锁输入的java字节码转换成SSA IR,以便进行优化。    
            示例:
            x1=4*1024经过常量折叠后变为x1=4096
            x1=4; y1=x1经过常量传播后变为x1=4; y1=4
            y1=x1*3经过强度削减后变为y1=(x1<<1)+x1
            if(2>1){y1=1;}else{y2=1;}经过死代码删除后变为y1=1
        具体来说,C2和Graal采用的是一种名为Sea-of-Nodes的IR,其特点用IR节点来代表程序中的值,并且将源程序基于变量的计算转换为基于值的计算。
       
   

posted @ 2020-09-23 14:11  小__七  阅读(277)  评论(0)    收藏  举报