ART虚拟机笔记

  1. 简介(参见:http://blog.csdn.net/luoshengyang/article/details/39256813
    ART是Android版本4.4中引入的新的运行时,并成为版本5.0及之后的默认运行时。
    Android的流畅性问题,有一部分原因就归结于它的应用程序和部分系统服务是运行虚拟机之上的,也就是运行在Dalvik虚拟机之上,而iOS的应用程序和系统服务都是直接执行本地机器指令的。
    ART之所以会比Dalvik快,是因为ART执行的是本地机器指令,而Dalvik执行的是Dex字节码,通过通过解释器执行。尽管Dalvik也会对频繁执行的代码进行JIT生成本地机器指令来执行,但毕竟在应用程序运行的过程中将Dex字节码翻译成本地机器机器指令也会影响到应用程序本身的执行,因此即使Dalvik使用了JIT(just-in-time),也在一定程度上也比不上直接就可以执行本地机器指令的运行时。
    ART才可以在不重新编译APK的基础上,直接对其进行加载和运行,这是由于APK在安装时被执行了AOT。AOT(Ahead Of Time)是相对JIT(Just In Time)而言的。也就是在APK运行之前,就对其包含的Dex字节码进行翻译,得到对应的本地机器指令,于是就可以在运行时直接执行了。这种技术不但使得我们可以不对原有的APK作任何修改,还可以使得这些APK只需要在安装时翻译一次,就可以无数次以本地机器指令的形式运行。这种技术与我们用C/C++语言编写一个程序,然后用GCC编译得到一个可执行程序,最后这个可执行程序就可以无数次地加载到系统执行,是差不多的。
  2. 分析
    在ART中,打包在APK里面的Dex字节码是通过LLVM翻译成本地机器指令的。LLVM是一个用来快速开发自己的编译器的框架系统。(LLVM可以参考它的作者之一Chris Lattner写的这篇文章:http://www.aosabook.org/en/llvm.html

在Dalvik运行时中,APK在安装的时候,安装服务PackageManagerService会通过守护进程installd调用一个工具dexopt对打包在APK里面包含有Dex字节码的classes.dex进行优化,优化得到的文件保存在/data/dalvik-cache目录中,并且以.odex为后缀名,表示这是一个优化过的Dex文件。在ART运行时中,APK在安装的时候,同样安装服务PackageManagerService会通过守护进程installd调用另外一个工具dex2oat对打包在APK里面包含有Dex字节码进翻译。这个翻译器实际上就是基于LLVM架构实现的一个编译器,它的前端是一个Dex语法分析器。翻译后得到的是一个ELF格式的oat文件,这个oat文件同样是以.odex后缀结束,并且也是保存在/data/dalvik-cache目录中。

当一个应用程序正在安装时,它的Dex文件中的Dalvik字节码被dex2oat工具编译为原生代码【注释 1:原生代码是指可以直接在特定处理器上直接运行的本地指令。】,并生成OAT格式的新文件,其中同时包括了Dalvik字节码和原生代码。 OAT格式是带有一些扩展的特殊ELF格式。
OAT文件有一个oatdata部分,其中包含已编译成原生代码的每个类的信息。原生代码驻留在一个特殊的部分,是用oatexec符号表示的偏移量所指的地方。因此,我们可以在oatdata部分及其编译的原生代码中,找到一个Java类的信息,通过oatexec标志。(在oat文件的动态段(dymanic section)中,还导出了三个标识符号oatdata、oatexec和oatlastword,见下图4,分别用来描述oatdata和oatexec段加段到内存后的起止地址。在oatdata段中,包含了两个重要的信息,一个信息是原来的classes.dex文件的完整内容,另一个信息引导ART找到classes.dex文件里面的类方法所对应的本地机器指令,这些本地机器指令就保存在oatexec段中。)
当一个应用程序被启动,ART运行时分析OAT文件并将文件加载到内存中。对于每个Java类对象,ART运行时有一个相应的C ++类对象的实例,来表示它。这个实例的第一个成员指向C ++的Class类的一个实例,这个类实例中包含了Java类的详细信息,包括字段,方法等等。每个Java方法由C ++的ArtMethod类的一个实例来表示,这个类中包含方法的地址,访问权限,这个方法所属的类,等等。C ++类ArtField用于表示一个类的变量,包括该变量所属的类,该变量在类中的索引,访问权限等。我们可以利用C ++对象,Class类,ArtMethod和ArtField来查找Java类的类,方法和变量的详细信息。
Android框架被编译成OAT文件,名为“system @ framework @ boot.oat”。 对于在设备上运行的所有应用程序,这个文件被加载到固定的内存范围,没有启用ASLR。 (摘自论文:Malton: Towards On-Device Non-Invasive Mobile Malware Analysis for ART)
APK在安装的时候,打包在里面的classes.dex文件会被工具dex2oat翻译成本地机器指令,最终得到一个ELF格式的oat文件。
只需要将dex文件的优化过程替换成dex文件翻译成本地机器码的过程,就可以轻松地在应用安装过程,无缝地将Dalvik虚拟机替换成ART运行时(即ART虚拟机)。

3.关键、核心
参考:http://blog.csdn.net/luoshengyang/article/details/18006645
http://blog.csdn.net/guoguodaern/article/details/60878829(ART运行时之method/field加载)

APK运行时,上述生成的oat文件会被加载到内存中,并且ART虚拟机可以通过里面的oatdata和oatexec段找到任意一个类的方法对应的本地机器指令来执行。
由于ART在查找类方法时,需要用到保存在oat文件的oatdata段的原dex文件内容,实质上就是要对dex文件进行解析,以获得相关的信息。这与Dalvik虚拟机在dex文件中查找类和方法信息的过程是一样的。
AOT(ahead of time),所谓AOT,就是在解释语言程序运行之前,就先将它编译成本地机器语言程序。AOT本质上是一种静态编译,它是相对于JIT而言的,也就是说,前者是在程序运行前进行编译,而后者是在程序运行时进行编译。

附:JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。

4.DVM
Dalvik虚拟机与Java虚拟机的最显著区别是它们分别具有不同的类文件格式以及指令集。Dalvik虚拟机使用的是dex(Dalvik Executable)格式的类文件,而Java虚拟机使用的是class格式的类文件。一个dex文件可以包含若干个类,而一个class文件只包括一个类。由于一个dex文件可以包含若干个类,因此它就可以将各个类中重复的字符串和其它常数只保存一次,从而节省了空间,这样就适合在内存和处理器速度有限的手机系统中使用。一般来说,包含有相同类的未压缩dex文件稍小于一个已经压缩的jar文件。
DVM使用的指令是基于寄存器的,JVM是基于堆栈的。

基于栈与基于寄存器的架构,谁更快?现在实际的处理器,大多都是基于寄存器的架构,从侧面反映出基于寄存器比基于栈的架构更与实际的处理器接近。但对于VM来说,源架构的求值 栈或者寄存器都可能是用实际机器的内存来模拟的,所以性能特性与实际硬件又有不同。一般认为基于寄存器架构的Dalvik VM比基于栈架构JVM执行效率更高,原因是:虽然零地址指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派 (instruction dispatch)次数与内存访问次数;访问内存是执行速度的一个重要瓶颈,二地址或三地址指令虽然每条指令占的空间较多,但总体来说可以用更少的指令完 成操作,指令分派与内存访问次数都较少。
(摘自知乎:https://www.zhihu.com/question/20207106

同一段Java代码对应的Java bytecode 与Dalvid bytecode的比较;

Dex文件进一步优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值