Android开发虽然基于Java,但是有自己的虚拟机,Android应用程序运行在ART/Dalvik虚拟机上,并非Java虚拟机。Android虚拟机其实也算是Java虚拟机,两者大部分特性是相同的,主要不同在于执行文件和执行指令集。
| Android虚拟机 | Java虚拟机 | |
|---|---|---|
| 执行文件格式 | .dex文件 | .class文件 |
| 指令集 | 基于寄存器 | 基于堆栈 |
虚拟机位于程序与硬件之间,将程序翻译成各种CPU可以执行的指令,而不用关心CPU架构,实现一次编译,到处运行的效果。
Java虚拟机是基于栈的,即每一个运行的线程,都有一个独立的栈,每调用一个方法,栈中就会多一个栈帧,最顶部的栈帧就是当前正在执行的方法,而虚拟机通过操作数栈对栈帧进行操作,所以栈就是方法调用的记录。

通过Java中编译生成的字节码Bytecode,可以看到Java程序是怎样一步一步的执行,详细过程可以参考Java随笔-方法执行与栈帧。
总得来讲就是程序计数器记录程序执行位置,操作数栈不断的压栈、出栈,局部变量表不停的存值、取值,操作数栈再不断的压栈、出栈,执行计算…。
Android虚拟机最开始默认使用的是Dalvik虚拟机执行.dex文件,从Android2.2开始支持即时编译JIT(Just In Time),在程序运行的过程中选择热点代码(经常执行的代码)进行编译或优化。Dalvik和JVM很相似,Android5.0后被废弃。
与JIT一起的还有Interpreter(解释执行),就是一边把字节码翻译成当前硬件平台的机器码一边执行。启动比较快,就是执行效率低下。

Android4.4开始在开发中选项中引入了ART(Android Runtime),在Android5.0后就完全使用ART。ART执行的是本地机器码,所以执行效率要比Dalvik快很多,能明显减少卡顿现象,这也是为什么废弃Dalvik使用ART的原因。
ART 采用了一种叫AOT (ahead of time) 来代替目前的在 runtime 时的 Interpreter 与 JIT。ART 不是等到App运行的时候才去运行dex文件,而是在App安装的时候就通过 AOT编译器 将.dex文件通过dex2oat编译为对应的.oat二进制文件,dex中的字节码会被编译成本地机器码。当用户点击App的启动图标时,ART直接加载.oat文件去执行。其中那个.oat文件就是一个ELF文件,其是当前机器的可执行的文件。所以ART在安装应用的时候要比Dalvik慢一点。

从Android N开始,Android开始混合使用AOT编译,解释执行,JIT。执行步骤如下:
Android虚拟机基于Java虚拟机,所以先说Java虚拟机。Android虚拟机基于寄存器,没有操作数栈,少了很多出入栈的操作。

Android虚拟机与JVM想比程序指令明显减少,数据移动数据次数也明显减少。
| 栈式VS寄存器式 | |
|---|---|
| 指令条数 | 栈式 > 寄存器式 |
| 代码尺寸 | 栈式 < 寄存器式 |
| 移植性 | 栈式 > 寄存器式 |
| 指令优化 | 栈式 < 寄存器式 |
| 解释器执行速度 | 栈式 < 寄存器式 |
| 代码生成难度 | 栈式 < 寄存器式 |
| 数据移动次数 | 栈式 > 寄存器式 |