Dalvik虚拟机简要介绍和学习计划

我们知道,Android应用程序是运行在Dalvik虚拟机里面的,并且每一个应用程序对应有一个单独的Dalvik虚拟机实例。除了指令集和类文件格式不同,Dalvik虚拟机与Java虚拟机共享有差不多的特性,例如,它们都是解释执行,并且支持即时编译(JIT)、垃圾收集(GC)、Java本地方法调用(JNI)和Java远程调试协议(JDWP)等。本文对Dalvik虚拟机进行简要介绍,以及制定学习计划。

老罗的新浪微博:,欢迎关注!

Dalvik虚拟机是由Dan Bornstein开发的,名字来源于他的祖先曾经居住过的位于冰岛的同名小渔村。Dalvik虚拟机起源于Apache Harmony项目,后者是由Apache软件基金会主导的,目标是实现一个独立的、兼容JDK 5的虚拟机,并根据Apache License v2发布。由此可见,Dalvik虚拟机从诞生的那一天开始,就和Java有说不清理不断的关系。

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

Dalvik虚拟机使用的指令是基于寄存器的,而Java虚拟机使用的指令集是基于堆栈的。基于堆栈的指令很紧凑,例如,Java虚拟机使用的指令只占一个字节,因而称为字节码。基于寄存器的指令由于需要指定源地址和目标地址,因此需要占用更多的指令空间,例如,Dalvik虚拟机的某些指令需要占用两个字节。基于堆栈和基于寄存器的指令集各有优劣,一般而言,执行同样的功能,前者需要更多的指令(主要是load和store指令),而后者需要更多的指令空间。需要更多指令意味着要多占用CPU时间,而需要更多指令空间意味着数据缓冲(d-cache)更易失效。

此外,还有一种观点认为,基于堆栈的指令更具可移植性,因为它不对目标机器的寄存器进行任何假设。然而,基于寄存器的指令由于对目标机器的寄存器进行了假设,因此,它更有利于进行AOT(ahead-of-time)优化。 所谓AOT,就是在解释语言程序运行之前,就先将它编译成本地机器语言程序。AOT本质上是一种静态编译,它是是相对于JIT而言的,也就是说,前者是在程序运行前进行编译,而后者是在程序运行时进行编译。运行时编译意味着可以利用运行时信息来得到比较静态编译更优化的代码,同时也意味不能进行某些高级优化,因为优化过程太耗时了。另一方面,运行前编译由于不占用程序运行时间,因此,它就可以不计时间成本来优化代码。无论AOT,还是JIT,最终的目标都是将解释语言编译为本地机器语言,而本地机器语言都是基于寄存器来执行的,因此,在某种程度来讲,基于寄存器的指令更有利于进行AOT编译以及优化。

事实上,基于寄存器和基于堆栈的指令集之争,就如精简指令集(RISC)和复杂指令集(CISC)之争,谁优谁劣,至今是没有定论的。例如,上面提到完成相同的功能,基于堆栈的Java虚拟机需要更多的指令,因此就会比基于寄存器的Dalvik虚拟机慢,然而,在2010年,Oracle在一个ARM设备上使用一个non-graphical Java benchmarks来对比Java SE Embedded和Android 2.2的性能,发现后者比前者慢了2~3倍。上述性能比较结论以及数据可以参考以下两篇文章:

1.Virtual Machine Showdown: Stack Versus Registers

2.Java SE Embedded Performance Versus Android 2.2

基于寄存器的Dalvik虚拟机和基于堆栈的Java虚拟机的更多比较和分析,还可以参考以下文章:

1.(software)

2.

3.

不管结论如何,Dalvik虚拟机都在尽最大的努力来优化自身,这些措施包括:

1. 将多个类文件收集到同一个dex文件中,以便节省空间;

2. 使用只读的内存映射方式加载dex文件,以便可以多进程共享dex文件,节省程序加载时间;

3. 提前调整好字节序(byte order)和字对齐(word alignment)方式,使得它们更适合于本地机器,以便提高指令执行速度;

4. 尽量提前进行字节码验证(bytecode verification),提高程序的加载速度;

5. 需要重写字节码的优化要提前进行。

这些优化措施的更具体描述可以参考Dalvik Optimization and Verification With dexopt一文。

分析完Dalvik虚拟机和Java虚拟机的区别之后,接下来我们再简要分析一下Dalvik虚拟机的其它特性,包括内存管理、垃圾收集、JIT、JNI以及进程和线程管理。

一. 内存管理

Dalvik虚拟机的内存大体上可以分为Java Object Heap、Bitmap Memory和Native Heap三种。

Java Object Heap是用来分配Java对象的,也就是我们在代码new出来的对象都是位于Java Object Heap上的。Dalvik虚拟机在启动的时候,可以通过-Xms和-Xmx选项来指定Java Object Heap的最小值和最大值。为了避免Dalvik虚拟机在运行的过程中对Java Object Heap的大小进行调整而影响性能,我们可以通过-Xms和-Xmx选项来将它的最小值和最大值设置为相等。

Java Object Heap的最小和最大默认值为2M和16M,但是手机在出厂时,厂商会根据手机的配置情况来对其进行调整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分别为16M、24M、32M 和48M。我们可以通过ActivityManager类的成员函数getMemoryClass来获得Dalvik虚拟机的Java Object Heap的最大值。

然后继续努力,把让自己跌倒的石头搬掉或绕过去,不就解决问题了吗

Dalvik虚拟机简要介绍和学习计划

相关文章:

你感兴趣的文章:

标签云: