概述

Android开发虽然基于Java,但是有自己的虚拟机,Android应用程序运行在ART/Dalvik虚拟机上,并非Java虚拟机。Android虚拟机其实也算是Java虚拟机,两者大部分特性是相同的,主要不同在于执行文件和执行指令集。

Android虚拟机

Java虚拟机

执行文件格式

.dex文件

.class文件

指令集

基于寄存器

基于堆栈

  • Java中xxx.java文件编译后生成.class文件。
  • Android中xxx.java代码编译后生成.dex文件,打包后再解压可以看到有很多.dex文件。
  • 一个.dex文件包含很多class,而一个.class文件中只有一个class。
  • 每一个Android应用程序都对应一个单独的Android虚拟机实例。

虚拟机

虚拟机位于程序与硬件之间,将程序翻译成各种CPU可以执行的指令,而不用关心CPU架构,实现一次编译,到处运行的效果。

Java虚拟机

Java虚拟机是基于栈的,即每一个运行的线程,都有一个独立的栈,每调用一个方法,栈中就会多一个栈帧,最顶部的栈帧就是当前正在执行的方法,而虚拟机通过操作数栈对栈帧进行操作,所以栈就是方法调用的记录。

android使用 buffer protocol Android使用的虚拟机是_java


通过Java中编译生成的字节码Bytecode,可以看到Java程序是怎样一步一步的执行,详细过程可以参考Java随笔-方法执行与栈帧。

总得来讲就是程序计数器记录程序执行位置,操作数栈不断的压栈、出栈,局部变量表不停的存值、取值,操作数栈再不断的压栈、出栈,执行计算…。

Android虚拟机

Dalvik

Android虚拟机最开始默认使用的是Dalvik虚拟机执行.dex文件,从Android2.2开始支持即时编译JIT(Just In Time),在程序运行的过程中选择热点代码(经常执行的代码)进行编译或优化。Dalvik和JVM很相似,Android5.0后被废弃。

与JIT一起的还有Interpreter(解释执行),就是一边把字节码翻译成当前硬件平台的机器码一边执行。启动比较快,就是执行效率低下。

android使用 buffer protocol Android使用的虚拟机是_Java_02

ART

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使用 buffer protocol Android使用的虚拟机是_Android_03

  • dexopt
    使用Dalvik加载dex文件时,会对dex文件进行验证和优化,dex被优化后就成了odex文件。
  • dex2oat
    ART在安装时对dex文件执行提前编译操作,编译为OAT文件,实际上也是ELF机器码。

混合编译

从Android N开始,Android开始混合使用AOT编译,解释执行,JIT。执行步骤如下:

  1. 首次安装APP时,不使用AOT编译,减少了安装时间。系统会通过Interpreter解释执行的方式启动APP,提升了启动速度。
  2. APP运行过程中热点代码使用JIT编译。
  3. 使用JIT编译的方法会被记录在配置文件Profile中。
  4. 当设备充电或处于空闲的时候,编译守护线程会对Profile中记录的方法进行AOT编译,将dex文件编译成oat文件。
  5. 再次运行APP时,直接执行oat文件。

比较

Android虚拟机基于Java虚拟机,所以先说Java虚拟机。Android虚拟机基于寄存器,没有操作数栈,少了很多出入栈的操作。

android使用 buffer protocol Android使用的虚拟机是_java_04


Android虚拟机与JVM想比程序指令明显减少,数据移动数据次数也明显减少。

栈式VS寄存器式

指令条数

栈式 > 寄存器式

代码尺寸

栈式 < 寄存器式

移植性

栈式 > 寄存器式

指令优化

栈式 < 寄存器式

解释器执行速度

栈式 < 寄存器式

代码生成难度

栈式 < 寄存器式

数据移动次数

栈式 > 寄存器式