大家知道Android是移动操作系统,移动设备的硬件条件决定了移动设备不适合采用很重量级的操作系统,尤其移动设备刚刚兴起的年代,硬件规格比之现在不可同日而语,所以一个标准规范的Java虚拟机跑在移动设备上是很吃力的,为此,Android就在Java虚拟机的基础上优化、改造,推出了Dalvik虚拟机。
Dalvik和JVM的比较
JVM是基于栈实现的虚拟机,方法调用和执行过程中的数据(如局部变量和中间结果)会存储在栈(操作数栈,下面会讲)中,Dalvik是基于寄存器实现的虚拟机,方法调用和执行过程中的数据(如局部变量和中间结果)会存储寄存器中。
基于栈的虚拟机:
1、代码移植性好,因为不同硬件的寄存器情况不同,但栈则只受限于通用内存,实现更简单。
2、指令更简短,但指令数量更多。默认就是操作 操作数栈(位于栈帧)中的数,所以不必指定操作数的位置。
基于寄存器的虚拟机:
1、实现更复杂。
2、指令长但数量少,性能高(寄存器速度更快)
为什么Android选择寄存器方案的虚拟机?
1、指令少,效率高。
2、数据移动次数少,临时结果存放次数少,更省内存,效率更快
3、映射真实的寄存器,效率高
Dalvik执行的是dex文件,Java虚拟机执行.class文件。
dex相比class文件的优势:
1、体积更小。如使用leb128(1到5个字节)来表示int类型;将多个class中的数据集中在一起
2、涉及到相互依赖时,class形式需要多次I/O不同的class文件,但dex文件则因为只有一个(其实也可能有多个dex文件,但相比class文件还是少得多)dex文件且包含了所有内容,所以读写次数减少。
Android 2.2之前,由Dalvik解释执行dex文件,达到让应用运行的效果;Android 2.2时加入了JIT(即时编译)技术,针对运行频率高的热代码转成本地机器码,这样下次再次执行该段代码时就直接执行本地机器码,提高了运行速度,但这样也带来了负面影响:转成机器码的操作也是需要CPU、内存、存储空间等资源的,这也在一定程度上拖慢了包括自身在内的整个系统的速度;另外JIT是每次重新启动应用后都会执行的,并不是这次该段代码转成机器码后,重启应用后就不用再转了。
到了Android 4.4,android 引入了ART -- Android Runtime,ART采用静态编译技术,即每次应用安装时就把大部分dex转成本地机器码,这样当应用启动后就可以直接使用机器码运行了,与JIT每次应用启动后都需执行相比,静态编译只需在安装时执行一次,大大提高了效率。缺点:导致应用安装速度变慢,每次应用安装(比如应用更新)都需要重新转成机器码,而且也同样需要占用更多的存储空间。在Android 4.4上ART还不是必选项,只是作为可选项。
到了Android 5.0,Android彻底抛弃(删除)了Dalvik,正式转向ART。
Android 7.0开始,JIT又回归了,采用了JIT和AOT混合使用的方式:应用安装时不再AOT,应用运行时先只靠解释执行,同时也会启用JIT来加快速度,但同时也会把热代码记录到profile文件里,等到手机空闲或充电时,再根据profile文件把热代码转成机器码。