文章目录
- Android 虚拟机
- Java虚拟机
- 基于栈的虚拟机
- 栈的执行流程
- Dalvik虚拟机
- 基于寄存器的虚拟机
- 寄存器的执行流程
- Java虚拟机与Dalvik虚拟机区别
- ART虚拟机
- Android 7.0的运行方式
Android 虚拟机
Java虚拟机
基于栈的虚拟机
每一个运行时的线程,都有一个独立的栈。
栈中记录了方法调用的历史,每一次方法调用,栈中都会产生一个栈帧。最顶部的栈帧称为当前栈帧,代表当前执行的方法。
基于栈道虚拟机通过操作数栈进行所有操作。
栈的执行流程
Java代码:
public void foo() {
int a = 1;
int b = 2;
int c = (a + b)*9;
}
编译为字节码:
执行过程:
第一步:执行第0行指令,将1压入操作数栈。
第二步:执行第1行指令,将栈顶的值1存入局部变量表。
第三步:执行第2行指令,将2压入操作数栈。
第四步:执行第3行指令,将2存入局部变量表。
第五步:执行第4行指令、第5行指令,将1和2压入操作数栈。
第六步:执行第6行指令,进行相加并压入操作数栈。
第七步:将int类型值9压入操作数栈。
第八步:执行第9行指令,进行相乘并压入操作数栈。
第九步:将栈顶值存入局部变量表。
Dalvik虚拟机
Android应用程序运行在Dalvik/ART虚拟机,并且每一个应用程序对应一个单独的Dalvik虚拟机实例。
Dalvik虚拟机本质也是一个Java虚拟机,只不过它执行的不是class文件而是dex文件。
基于寄存器的虚拟机
基于寄存器的虚拟机没有操作数栈,但是有很多虚拟寄存器。
与JVM相似,在Dalvik虚拟机中每个线程都有自己的寄存器和调用栈,方法调用的活动记录以帧为单位保存在调用栈上。
寄存器的执行流程
dex字节码:
执行过程:
第一步:执行第0行指令,将1放入寄存器v0。
第二步:执行第1行指令,将2放入寄存器v1。
第三步:执行第2行指令,相加后将结果放入寄存器v0。
第四步:执行第3行指令,将v0和9相乘,并将结果放入v0。
Java虚拟机与Dalvik虚拟机区别
Java虚拟机 | Dalvik虚拟机 | |
---|---|---|
指令集 | Java字节码 (基于栈) | Dalvik字节码 (基于寄存器) |
文件格式 | .class 文件 | .dex 文件 |
单条指令长度 | 短 | 很长 |
同样逻辑指令条数 | 多 | 少 |
同样逻辑数据移动次数 | 多 | 少 |
同样逻辑临时结果存储次数 | 多 | 少 |
所以为什么Android平台基于寄存器的设计?
- 指令条数少,所以执行的效率更快!
- 数据移动次数少、临时结果存放次数少,所以更省内存和执行效率更快!
- 映射真实机器的寄存器,所以执行效率更快!
ART虚拟机
Dalvik虚拟机执行的是dex字节码,解释执行。从Android 2.2版本开始,支持JIT即时编译(Just In Time)在程序运行的过程中进行选择热点代码(经常执行的代码)进行编译或者优化。
而ART(Android Runtime) 是在 Android 4.4 中引入的一个开发者选项,也是 Android 5.0 及更高版本的默认 Android 运行时。ART虚拟机执行的是本地机器码。Android的运行时从Dalvik虚拟机替换成ART虚拟机,并不要求开发者将自己的应用直接编译成目标机器码,APK仍然是一个包含dex字节码的文件。
Dalvik下应用在安装的过程,会执行一次优化,将dex字节码进行优化生成odex文件。而Art下将应用的dex字节码翻译成本地机器码的最恰当AOT时机也就发生在应用安装的时候。
在Android 7.0中ART 引入了预先编译机制(Ahead Of Time),在安装时,ART 使用设备自带的 dex2oat 工具来编译应用,dex中的字节码将被编译成本地机器码。
Android 7.0的运行方式
ART 使用预先 (AOT) 编译,并且从 Android N混合使用AOT编译,解释和JIT。
1、最初安装应用时不进行任何 AOT 编译(安装又快了),运行过程中解释执行,对经常执行的方法进行JIT,经过 JIT 编译的方法将会记录到Profile配置文件中。
2、当设备闲置和充电时,编译守护进程会运行,根据Profile文件对常用代码进行 AOT 编译。待下次运行时直接使用。