个人笔记

Android系统下编译模式的演变

Java的执行方式

Java虚拟机有3种执行方式,分别是解释执行、编译执行和混合模式,默认情况下处于混合模式中。使用命令行java –version可以查看虚拟机的执行模式。

Java编译模式

  • interpreted mode表示解释执行模式,全部代码均解释执行。

  • compiled mode表示编译执行模式,和解释执行模式相反,对于所有的方法,无论是否是热点代码,都会被编译执行。

  • mixed mode表示混合模式,部分代码会被解释执行,也可能被编译执行。虚拟机决定热点(高频、反复使用)代码是否需要编译执行。

什么是JIT和AOT

JIT(Just-in-time)

JIT属于动态编译编译器,通常也被称为即时编译器。Java虚拟机默认使用的编译技术,也就是前面提到的混合编译模式,相比于解释执行全部字节码的效率低下,编译执行不加区分的编译转化成机器码。而混合模式较好的结合了二者的优势,对部分热点代码进行编译优化,在执行效率上接近C/C++。

jit工作过程

从图中看出整个执行过程如下:

1、源代码经javac编译成字节码,即class文件

2、字节码经过JIT环境变量进行判断,是否属于“热点代码”(多次调用的方法,或循环等)

3、如是,走JIT编译为具体硬件处理器(如sparc、intel)机器码

4、如否,则直接由解释器解释执行

5、操作系统及类库调用

6、硬件

运行时会将JIT编译过的机器码保存起来,第二次直接执行,但是识别热点代码也需要一个准备的过程。同时,对于部分只会被执行一次的代码,编译就是浪费效率。

AOT(Ahead-of-time)

AOT,就是在程序运行之前先将代码编译成本地机器语言的程序。AOT本质上是一种静态编译,它是相对于JIT而言的,也就是说,前者是在程序运行前进行编译,而后者是在程序运行时进行编译。

静态编译可以在运行时执行最大数量的本地代码,无需占用运行时间。但是编译方法越多,代码占用的内存也越多,大量代码可能很少甚至不会执行,编译器也无法对代码结构做优化。

Android系统上的演变

早期Android的Dalvik虚拟机在架构上保持跟JVM高度相似,如图:

虚拟机区别

  • JNI_GetDefaultJavaVMInitArgs –获取虚拟机的默认初始化参数
  • JNI_CreateJavaVM – 在进程中创建虚拟机实例
  • JNI_GetCreatedJavaVMs – 获取进程中创建的虚拟机实例

从最早期的解释执行到现在的混合编译,经历了多个阶段:

Android系统版本

尤其是在4.4之后,性能上有了较大提升。引入ART取代了Dalvik。ART的主要特征之一就是安装时对应用的AOT编译。优点是优化产生的本地代码性能更好,执行起来需要更少的电量。劣势在于安装文件所需的空间和时间。在5.0和6.0中,大的应用需要数分钟才能安装完。

AOT JIT对比

保持dex的向下兼容
接口不变

7.0时代,ART中有一种新的、更快的解释器,通过一种新的JIT完成,但是这种JIT的信息不是持久化的。取而代之的是,代码在执行期间被分析,分析结果保存起来。然后,当设备空转和充电的时候,ART会执行针对“热代码”进行的基于分析的编译和优化。这个过程也属于AOT,可以理解为全时段的编译(All-Of-the-Time compilation)
混合运行时1

工作流程:

混合运行时2

系统会收集使用代码的各种信息(用户使用习惯),存储在profiles文件夹,当收集到一定量之后,达到系统的触发条件,进行dex2oat编译成机器码直接执行。这个过程不是一次性的,而是可以进行多次的,随着收集到应用运行时的代码各种信息越多,那么代码编译的质量就越高,效率越高,能不断更新编译的机器语言,达到执行最优化。

混合使用AOT、解释、JIT的策略,优点也很明显:

  • 应用安装时间大大缩短
  • 无需要优化,系统升级更快
  • 应用的内存占用更小
  • 改善了性能、更低的电池消耗

总结

混合模式也不是全能,达到最佳性能同样需要一个时间过程。没有万能的方案,每种模式都有其自身的优缺点,Android也是根据系统生态、硬件水平等方面的因素做出权衡。