Android其实基于Java语言的,所以同理,想要运行一段Android代码,也要经过多个步骤,将Android源代码转换成机器可以执行的机器代码。

但是这个转换过程在Android的不同版本中实现不尽相同:

Android 1.0(2008 年):采用一个名为 Dalvik 的虚拟机,并且集成了一个解释器。当 App 运行时,就会调用这个解释器,对代码进行逐句解释,速度很慢。

Android 2.2(2010 年):引入 JIT(Just In Time)即时编译机制,当 App 运行时,会将用户经常使用的功能编译为机器能直接执行的 010101 机器码,不用一句一句地去翻译。当出现不常用的功能时,再调用解释器来翻译;这样速度加快,但每次启动 App 都要重新编译一次,不能一劳永逸。
 

Android 5.0(2014 年 10 月):将虚拟机 Dalvik 换成 ART(Android Run Time),将 JIT 的编译器替换成 AOT(Ahead of Time)。如此,App 在下载后安装到手机上时同时把能编译的代码先编译成机器听得懂的 101010;剩下不太好翻译的代码,就在用户使用时再叫醒解释器来翻译。如此,不用每次打开 App 都需要编译,但安装 App 的时间有点长,而且占用手机空间。
 

Android 7.0(2016 年):采用混合编译机制,安装时先不编译中间代码,而是在用户空闲时将能够编译成机器码的那部分代码,通过 AOT 编译器先静态编译了。如果 AOT 还没来得及编译或者不能编译,再调用 JIT+ 解释器。这种机制,相当于用时间换空间,既缩短了用户安装 APP 的等待时间,又将虚拟机里编译器和解释器能做的优化提升到最大效率了。
 

Android编译的问题
可以看到,从2008年的Android 1.0开始,Android在编译优化上面在一直下功夫。

当前的 Android 采用的是解释执行 + JIT + AOT 的综合模式,在 空间占用+安装速度+运行速度 上已经达到了一个很好的平衡。

但是Android的编译问题一直被诟病。尽管在后续的Android 8.0 上改进了解释器,解释模式执行效率大幅提升;Android 10.0 上提供了预先放置热点代码的方式,应用在安装的时候就能知道常用代码会被提前编译。

但是,目前来看,无论如何,Android都没能摆脱这样一个前提:即应用在被打包成 APK 的时候,采用的还是 Java 代码。换句话说,在 APK 变成用户可应用的过程中,还经历了一个在 Android 系统内部的编译过程,这是一个绕不过的坎。