(1) Dalvik VM和JVM 的第一个区别是 Dalvik VM是基于寄存器的架构(reg based),而JVM是栈机(stack based)。reg based VM的好处是可以做到更好的提前优化(ahead-of-time optimization)。 另外reg based的VM执行起来更快,但是代价是更大的代码长度。
(2) 另外一个区别是Dalvik可以允许多个instance 运行,也就是说每一个Android 的App是独立跑在一个VM中.这样做的好处是一个App crash只会影响到自身的VM,不会影响到其他。 Dalvik的设计是每一个Dalvik的VM都是Linux下面的一个进程。那么这就需要高效的IPC。另外每一个VM是单独运行的好处还有可以动态active/deactive自己的VM而不会影响到其他VM
(3) 接下来就是关于版权之类争论。(可以参看下面文章)
既然reg based VM有那么多好处,为什么之前设计JAVA的人没有采用reg based而是采用stack based的呢? 原来stack based的VM也有其优点,就是它不对host平台的reg数量做假设,有利于移植到不同的平台。而Dalvik则不关心这些,因为它本来就是为ARM这样的多reg平台设计的。另外Dalvik被移植到x86也说明,即使是x86这种reg很少的平台,reg based的VM也是没有问题的。
下面着重说下DVM的优势:
1、在编译时提前优化代码而不是等到运行时
2、 虚拟机很小,使用的空间也小;被设计来满足可高效运行多种虚拟机实例。
3、常量池已被修改为只使用32位的索引,以 简化解释器
JVM 的字节码主要是零地址形式的,概念上说JVM是基于栈的架构。Google Android平台上的应用程序的主要开发语言是Java,通过其中的Dalvik VM来运行Java程序。为了能正确实现语义,Dalvik VM的许多设计都考虑到与JVM的兼容性;但它却采用了基于寄存器的架构,其字节码主要是二地址/三地址的混合形式。
基于栈与基于寄存器的 架构,谁更快?
现在实际的处理器,大多都是基于寄存器的架构,从侧面反映出基于寄存器比基于栈的架构更与实际的处理器接近。但对于VM来说,源架构的求值 栈或者寄存器都可能是用实际机器的内存来模拟的,所以性能特性与实际硬件又有不同。一般认为基于寄存器架构的Dalvik VM比基于栈架构JVM执行效率更高,原因是:虽然零地址指令更紧凑,但完成操作需要更多的load/store指令,也意味着更多的指令分派 (instruction dispatch)次数与内存访问次数;访问内存是执行速度的一个重要瓶颈,二地址或三地址指令虽然每条指令占的空间较多,但总体来说可以用更少的指令完 成操作,指令分派与内存访问次数都较少。
我们从下面的截图可以明了的看到与同一段Java代码对应的Java bytecode 与Dalvid bytecode的比较:
网上一些文章在讨论 Dalvik 时,大都简单提及 Dalvik 执行速度比 JVM 快,但移植性稍差。这里 我们延伸探讨一下。在一个解释器上执行 VM 指令,包含三个步骤,指令分派、访问操作数和执 行计算。 指令分派(Instructions dispatch)负责从内存中读取 VM 指令,然后跳转到相应的解释器代码 指令分派 中。上面提到过,完成同样的事情,基于栈的虚拟机需要更多的指令,意味着更多的指令分派和 内存访问次数,这是 JVM 的执行性能不如 Dalvik VM 的原因之一。
访问操作数 访问操作数(Operands access)是指读取和写回源操作数和目的操作数。Dalvik VM 通过虚拟 操作数 寄存器来访问操作数, 由于具有相近的血缘, Dalvik 的虚拟寄存器在映射到物理寄存器方面具有 更充分的优势, 这也是 Dalvik VM 性能较佳的一个原因。 JVM 的操作数通过操作数栈来访问, 而 因为指令中没有使用任何通用寄存器,在虚拟机的实现中可以比较自由的分配实际机器的寄存 器,因而可移植性高。作为一个优化,操作数栈也可以由编译器映射到物理寄存器上,减少数据 移动的开销。 指令执行(Instructions compute)这个似乎没什么可解释的,老老实实执行就行。 指令执行
一个应用中会定义很多类, 编译完成后即会有很多相应 的CLASS文件,CLASS文件 间会有不少冗余的信息。
dex字节码和标准Java的字节码(Class)在结构上的一个区别是dex字节码将多个文件整合成一个,这样,除了减少整体的文件尺寸,I/O操作,也提高了类的查找速度。
原来每个类文件中的常量池现在由DEX文件中一个常量池来管理。
DEX文件可以进行进一步优化。优化主要是针对以下几个方面:
1、调整所有字段的字节序(LITTLE_ENDIAN)和对齐结构中的没一个域
2、验证DEX文件中的所有类
3、对一些特定的类进行优化,对方法里的操作码进行优化
优化
优化后的文件大小会有所增加,应该是原DEX文件的1-4倍。 odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化
每一个Android应用都运行在一个Dalvik虚拟机实例里,而每一个虚拟机实例都是一个独立的进程空间。每个进程之间可以通信(IPC,Binder机制实现)。虚拟机的线程机制,内存分配和管理,Mutex等等都是依赖底层操作系统而实现的。
不同的应用在不同的进程空间里运行,当一个虚拟机关闭或意外中止时不会对其它虚拟机造成影响,可以最大程度的保护应用的安全和独立运行。