java虚拟机

dex编译相关:JIT、AOT

2017-12-20  本文已影响0人  yizhanzjz

前言

  在android的源码中看到了jit相关的代码,感觉jit这词儿有点儿眼熟,就查了一下其相关资料,顺带了解了一下android dex编译技术的变迁史。下面是总结,以问题为引导来说。

总结

  什么是JIT ?

  JIT,即“Just In Time”,翻译过来就是“即时编译技术”。android在2.2版本引入此技术,主要是用来提高程序的执行效率的。既然是编译技术,那它具体编译的是什么?又是什么时候执行此操作的?JIT是在程序运行期间执行,可将java字节码编译成机器码,将java指令编译成cpu可执行的微处理器指令。

  那它又是怎么提高程序的执行效率的?2.2版本之前的android在程序运行时,代码的执行都需要先通过解释器将字节码转换成机器码,而引入了JIT后,对于会多次执行到的代码(比如某个类的函数、某一个经常使用到的执行路径相关的代码,就是所谓的“热点函数”、“热点trace”),JIT会将其编译成机器码。下次再执行此代码时就直接执行机器码,从而提高了代码的执行效率。

  为什么只是对热点函数、热点trace进行JIT编译,而不是全部的字节码?首先,字节码的大部分代码一般不会总是执行到(即执行频率低),而JIT是在程序运行期间编译,编译时又需要时间,在程序运行期间花时间编译一般不会执行到的代码,这不是一个好的选择。所以,JIT只编译热点函数、热点trace,对于非热点的代码仍旧在用到时用解释器去解释成机器码然后执行就可以了。

  还有一个点,JIT编译而来的机器码是存储到内存中的,不是在硬盘上。所以,在应用重新启动时,所有的热点代码也都需要使用jit重新编译成机器码。

  网上找到一段关于JIT在代码层面实现逻辑的说明,个人认为很好:“每启动一个应用程序,都会相应地启动一个dalvik虚拟机,启动时会建立JIT线程,一直在后台运行。当某段代码被调用时,虚拟机会判断它是否需要编译成机器码,如果需要,就做一个标记,JIT线程不断判断此标记,如果发现被设定就把它编译成机器码,并将其机器码地址及相关信息放入entry table中,下次执行到此就跳到机器码段执行,而不再解释执行,从而提高速度”。

  JIT是Dalvik虚拟机下的编译模式,随着ART在4.4版本之后替代Dalvik,编译模式也由JIT变为了AOT(4.4版本JIT)。

小结:

  什么是AOT?

  AOT,即“Ahead Of Time”,翻译过来就是“预编译”。这个技术在4.4版本上就可以使用了,是ART的编译模式。为什么叫“预编译”?因为它是在应用安装时就将字节码编译成了机器码然后存放在本地(可以理解为“硬盘”)了。这样程序运行时就可以直接从本地取到机器码然后执行,大大提高了代码的执行效率。

  JIT会在程序运行期间进行编译,执行效率并没有理论上那么高。而AOT直接在应用安装时就编译了,无需在程序运行期间编译,这是AOT的一个优势。但它也有弊端,比如说应用安装时就编译,会导致应用包安装的时间变长;编译的机器码存到了本地,就会导致应用占用的本地存储空间多了代码包的20%左右。

  AOT作为默认的编译模式,也只是在android 5.x、6.x版本,7.0版本开始使用混合模式。

小结:

  android 7.0及之后的编译模式是怎样的?

  7.0版本采用的是hybird的模式,也就是JIT+AOT+解释器的结合。应用安装时不再编译,直接安装。代码执行时采用JIT的方式,对于热点trace和热点代码进行编译并产生profile文件,但这种JIT产生的编译不是持久化的。当手机进入空置或者充电状态时,系统隔一段时间就扫描一下app的profile文件,基于此profile文件制定的热点trace或者热点代码进行编译并进行持久化处理。待应用再次运行时,如本地有相关机器码,就直接运行本地的机器码而不再进行JIT编译。

  此处的AOT,不再指“Ahead Of Time”,而是指“All Of the Time”。

  这种混合模式的好处是,因为不再进行安装时编译,安装会变得很快;在空置或充电等状态下进行了编译,编译过的热点代码或热点trace不会再进行重复编译,执行效率也会提升。缺点是,应用前几次代码执行,效率可能一般;用户操作应用的次数越多,这种代码执行的效率越明显。

参考资料:

上一篇下一篇

猜你喜欢

热点阅读