《Dalvik虚拟机简介及架构级移植优化方向》由会员分享,可在线阅读,更多相关《Dalvik虚拟机简介及架构级移植优化方向(20页珍藏版)》请在金锄头文库上搜索。
1、LOGOAndroidDalvik虚拟机初识及架构简析LOGO嵌入式系统概述嵌入式系统概述Dalvik虚拟机与Java虚拟机的区别Dalvik虚拟机源码目录简析Dalvik虚拟机专有工具的功能及使用Dalvik虚拟机初识及基本特性1234本本节节主主要要内内容容Dalvik虚拟机核心执行引擎5Dalvik虚拟机的移植及优化方向LOGO1、Dalvik虚拟机初识及基本特性什么是Dalvik虚拟机?让我们从认识Java虚拟机开始:Java虚拟机(JVM)是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。它有自己完善的硬件架构(如处理器、堆栈、寄存器等),还具有相应的指令
2、系统。使用“Java虚拟机”程序就是为了支持与操作系统无关、在任何系统中都可以运行的程序。Davlik虚拟机同Java虚拟机同样是运行Java程序的虚拟机,但Davlik虚拟机具有其独特特性:Dalvik虚拟机是Android程序的虚拟机,是Android中Java程序的运行基础。其指令集基于寄存器基于寄存器架构,执行其特有的文件格式特有的文件格式dex字节码来完成对象生命周期管理、堆栈管理、线程管理、安全异常管理、垃圾回收等重要功能。它的核心内容是实现库(libdvm.so),架构由C语言实现。依赖于Linux内核的一部分功能线程机制、内存管理机制,能高效使用内存,并在低速CPU上表现出的高
3、性能。每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。让我们看看Dalvik虚拟机处在Android系统架构的什么位置:LOGOLOGO2、Dalvik虚拟机与Java虚拟机的区别然而:Dalvik VM Java VMI.dalvik基于寄存器,而JVM基于stackII.Dalvik执行的是特有的DEX文件格式,而JVM运行的是*.class文件格式。优势:1、在编译时提前优化代码而不是等到运行时2、虚拟机很小,使用的空间也小;被设计来满足可高效运行多种虚拟机实例。3、常量池已被修改为只使用32位的索引,以简化解释器LOGOJVM的字
4、节码主要是零地址形式的,概念上说JVM是基于栈的架构。GoogleAndroid平台上的应用程序的主要开发语言是Java,通过其中的DalvikVM来运行Java程序。为了能正确实现语义,DalvikVM的许多设计都考虑到与JVM的兼容性;但它却采用了基于寄存器的架构,其字节码主要是二地址/三地址的混合形式。基于栈与基于寄存器的架构,谁更快?现在实际的处理器,大多都是基于寄存器的架构,从侧面反映出基于寄存器比基于栈的架构更与实际的处理器接近。但对于VM来说,源架构的求值栈或者寄存器都可能是用实际机器的内存来模拟的,所以性能特性与实际硬件又有不同。一般认为基于寄存器架构的DalvikVM比基于栈
5、架构JVM执行效率更高,原因是:虽然零地址指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派(instructiondispatch)次数与内存访问次数;访问内存是执行速度的一个重要瓶颈,二地址或三地址指令虽然每条指令占的空间较多,但总体来说可以用更少的指令完成操作,指令分派与内存访问次数都较少。我们从下面的截图可以明了的看到与同一段Java代码对应的Javabytecode与Dalvidbytecode的比较。LOGOLOGODalvik字节码以16位为单元(或许叫“双字节码”更准确)。上面代码中有5条指令,其中mul-int/lit8指令占2单元,其余每条都只
6、占1单元,共6单元=12字节。Java字节码以1字节为单元。上面代码中有11条指令,每条都只占1单元,共11单元=11字节。基于寄存器与基于栈的区别更详细的介绍见补充文档。基于寄存器与基于栈的区别更详细的介绍见补充文档。LOGODalvik专有的专有的DEX文件格式文件格式一个应用中会定义很多类,编译完成后即会有很多相应的CLASS文件,CLASS文件间会有不少冗余的信息。dex字节码和标准Java的字节码(Class)在结构上的一个区别是dex字节码将多个文件整合成一个,这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。原来每个类文件中的常量池现在由DEX文件中一个常量池来管理
7、。DEX文件可以进行进一步优化。优化主要是针对以下几个方面:1、调整所有字段的字节序(LITTLE_ENDIAN)和对齐结构中的没一个域2、验证DEX文件中的所有类3、对一些特定的类进行优化,对方法里的操作码进行优化DEX字节码的生成过程将在后续的专有工具介绍中给出。字节码的生成过程将在后续的专有工具介绍中给出。为什么弃用已有的字节码文件(CLASS文件)而采用新的格式呢?LOGO3、Dalvik虚拟机源码目录简析通过以上的介绍,我们对DalvikVM能实现的功能以及为什么需要这么一个虚拟机有了初步的认识。观其内部,AndroidVM的架构是什么样子的呢?在源码中,DalvikVM相关的内容在
8、Android中是一个独立的代码路径:dalvik/,其中包含了目标机和主机的内容。其主要的目录如下所示:Dalvik/|-Dx|-Vm|-Arch|-Mterp|-Native|-Compiler|-DalvikvmDalvik/dx目录的内容是dx工具库,其最终将dx专有工具(可执行文件)。另外与dx目录同级的文件夹dexdump、tools同样对应几个专有工具。Dalvik/vm目录的内容是虚拟机核心实现,其最终将生成libdvm.so(Dalvik虚拟机)。Davlik/dalvikvm目录中的内容是虚拟机的入口程序,会生成dalvilvm可执行程序。LOGO由于Dalvik中许多代码
9、直接来源于ApacheHarmony项目,因此,通过了解ApacheHarmony项目对我们认识DalvikVM有很大的帮助。ApacheHarmony技术架构如下所示:LOGO从应用程序的执行流程来看DalvikVM的组成部分:DX工具:由Java编译器编译后的.class转换成DE格式。类加裁器:1、原始加载器,加载native实现的类;2、加载器object,加载java实现的类。(所有process共享)执行引擎(解释器):根据其自身的一套指令集对dalvikbytecode进行解释。另外包括在此流程中实现的内存管理及线程机制LOGODEX文件的生成:Android系统和Dalvik虚
10、拟机提供了工具(DX)在把Java源代码编译成CLASS文件后使用DX工具DEX文件的结构相对于.jar更加紧凑但是为了获得高效率我们还得进一步对.dex进行优化。LOGO4、Dalvik虚拟机专有工具的功能及使用Dalvik的虚拟机专有工具的功能其实很简单:改造并优化java字节码。一般来说,启动一个Dalvik虚拟机需要启动一个Android应用程序来完成,其实我们可以直接使用Dalvik虚拟机:dx工具可以单独剥离出来使用。如,我们在pc上用java编译器把java源码编译成class字节码(这个步骤也可以在Linux服务器上完成),然后在linux上直接使用dx把该class字节码变成
11、dex字节码(可以通过dx直接生成打包好的DEX格式的文件,如.jar等),如下有一个简单例子:%echoclassFoopublicstaticvoidmain(Stringargs)System.out.println(Hello,world);Foo.java%javacFoo.java%dx-dex-output=foo.jarFoo.class%adbpushfoo.jar/sdcard%adbshelldalvikvm-cp/sdcard/foo.jarFLOGOjava语言是解释型语言,它是以跨平台换取执行效率为代价的。跨平台性体现在编译的跨平台性和运行跨平台性。编译的跨平台体现
12、在源程序不限制于在某一平台进行编译,运行的跨平台性体现在编译出来的可执行程序也不限制于在某一平台上运行。这样神奇是特性是不是特别具有吸引力呢?现在我们把重点放在运行的跨平台性。运行的跨平台性是以牺牲虚拟机的平台性相关性为代价的,而这正是我们需要解决的问题,因为官方并未提供unicore架构的虚拟机。Dalvik虚拟机的平台相关性集中的体现在的执行引擎上,它是Dalvik虚拟机的核心部分,Dex字节码就是在这个部分解释执行。平台相关性问题我们先暂且搁置,因为在下一部分会重点分析Dalvik虚拟机的移植。先来了解一下解释器是怎么工作的:5、Dalvik虚拟机核心执行引擎LOGO如Dex字节码add
13、-int/2addr对应的架构汇编如下:movr22,rINST#8r22#12 r3-Bandr22,r22,#15GET_VREG(r1,r3) r1-vBGET_VREG(r0,r22)r0-vAFETCH_ADVANCE_INST(1) advancerPC,loadrINSTaddr0,r0,r1GET_INST_OPCODE(ip)extractopcodefromrINSTSET_VREG(r0,r22)vAA-r0GOTO_OPCODE(ip) jumptonextinstruction#defineGET_VREG(_reg,_vreg)ldw_reg,rFP+,_vreg#
14、2#defineFETCH_ADVANCE_INST(_count)ldh.wrINST,rPC+,#(_count*2)#defineGET_INST_OPCODE(_reg)and_reg,rINST,#255#defineSET_VREG(_reg,_vreg)stw_reg,rFP+,_vreg#2#defineGOTO_OPCODE(_reg)addpc,rIBASE,_reg#6对应的C实现是:HANDLE_OP_X_INT_2ADDR(OP_AND_INT_2ADDR, and, &, 0) OP_END#defineOP_ENDLOGO对应的C实现是:#defineHANDLE
15、_OP_X_INT_2ADDR(_opcode,_opname,_op,_chkdiv)HANDLE_OPCODE(_opcode/*vA,vB*/)vdst=INST_A(inst);vsrc1=INST_B(inst);ILOGV(|%s-int-2addrv%d,v%d,(_opname),vdst,vsrc1);if(_chkdiv!=0)s4firstVal,secondVal,result;firstVal=GET_REGISTER(vdst);secondVal=GET_REGISTER(vsrc1);if(secondVal=0)EXPORT_PC();dvmThrowExce
16、ption(Ljava/lang/ArithmeticException;,dividebyzero);GOTO_exceptionThrown();if(u4)firstVal=0x80000000&secondVal=-1)if(_chkdiv=1)result=firstVal;/*division*/elseresult=0;/*remainder*/elseresult=firstVal_opsecondVal;SET_REGISTER(vdst,result);elseSET_REGISTER(vdst,(s4)GET_REGISTER(vdst)_op(s4)GET_REGIST
17、ER(vsrc1);FINISH(1);LOGO6、Dalvik虚拟机的移植及优化方向Dalvik虚拟机整个架构真正意义上与架构相关的地方只有一个,那就是JNICallbridge。这是因为java引入了JNI机制,实现了java到本地方法的直接调用。这个调用关系就涉及以参数传递的问题,如X86架构的参数全是从右至左压栈传递,而ARM架构的参数传递则要遵循ATPCS。因此,Dalvik虚拟机的移植到这一步可以说算完成了。注意,此时解释器是C语言现实的。JNICallbridge的移植需要认真的分析一下HintsEABI.c这个文件,因为这个文件函数dvmPlatformInvokeHints会
18、解析要地方法列表的第二项:如一个本地方法列表为:staticJNINativeMethodmethods=“simple”,“(II)I”,(void*)add,;接着,被分析提取出来的参数列表会传递给dvmPlatformInvoke这个函数。为了效率,这个函数一般是用汇编完成的。它所在的文件名为:CallEABI.SCallEABI.S和HintsEABI.c位于android/dalvik/vm/arch/xx_ARCHLOGO从前面的介绍知道Dalvik虚拟机最大的优化跨平台性,但以此换取执行效率相对低下的劣势。因此带来一项新的挑战Dalvik虚拟机的优化。从目前较成熟的技术来说,Dalvik虚拟机的优化可以从两个大的方面进行。一个方向是软件优化,包括解释器的汇编重写解释器的汇编重写和引入引入JIT技术技术;另一个方面就是硬件优化了。我们知道,java字节码或是dex字节码,它们的表现形式相当接近汇编,汇编语言能够由CPU直接执行,字节码为什么不可以呢?事实上java早已实现该技术JazelleDBX(DirectBytecodeeXecution)技术,即允许它们在某些架构的硬件上加速执行Javabytecode。因此,在dalvik虚拟机上实现类类Jazelle功能完全是可行的。由于这涉及以硬件的最底层机制的实现,所以目前只能作为一项展望了。LOGO