Google于2007年底正式发布了Android SDK,Dalvik虚拟机也第一次进入了人们的视野。它的作者是丹.伯恩斯坦(Dan Bornstein)。Dalvik虚拟机作为Android平台的核心组件,拥有如下几个特点:

  • 体积小,占用内存空间小;

  • 专有的DEX可执行文件格式,体积更小,执行速度更快;

  • 常量池采用32位索引值,寻址类方法名,字段名,常量更快;

  • 基于寄存器架构,并拥有一套完整的指令系统;

  • 提供了对象生命周期管理,堆栈管理,线程管理,安全和异常管理以及垃圾回收等重要功能;

  • 所有的Android程序都运行在Android系统进程里,每个进程对应着一个Dalvik虚拟机实例。

1. Dalvik虚拟机与Java虚拟机的区别

Dalvik虚拟机与传统的Java虚拟机有着许多不同点,两者并不兼容,它们显著的不同点主要表现在以下几个方面:

  • Java虚拟机运行的是Java字节码,Dalvik虚拟机运行的是Dalvik字节码。传统的Java程序经过编译,生成Java字节码保存在class文件中,Java虚拟机通过解码class文件中的内容来运行程序。而Dalvik虚拟机运行的是Dalvik字节码,所有的Dalvik字节码由Java字节码转换而来,并被打包到一个DEX(Dalvik Executable)可执行文件中。Dalvik虚拟机通过解释DEX文件来执行这些字节码。

  • Dalvik可执行文件体积小。Android SDK中有一个叫dx的工具负责将Java字节码转换为Dalvik字节码。dx工具对Java类文件重新排列,消除在类文件中出现的所有冗余信息,避免虚拟机在初始化时出现反复的文件加载与解析过程。一般情况下,Java类文件中包含多个不同的方法签名,如果其他的类文件引用该类文件中的方法,方法签名也会被复制到其类文件中,也就是说,多个不同的类会同时包含相同的方法签名,同样地,大量的字符串常量在多个类文件中也被重复使用。这些冗余信息会直接增加文件的体积,同时也会严重影响虚拟机解析文件的效率。消除其中的冗余信息,重新组合形成一个常量池,所有的类文件共享同一个常量池。由于dx工具对常量池的压缩,使得相同的字符串,常量在DEX文件中只出现一次,从而减小了文件的体积。

  • Java虚拟机与Dalvik虚拟机架构不同。Java虚拟机基于栈架构,程序在运行时虚拟机需要频繁的从栈上读取或写入数据,这个过程需要更多的指令分派与内存访问次数,会耗费不少CPU时间,对于像手机设备资源有限的设备来说,这是相当大的一笔开销。Dalvik虚拟机基于寄存器架构。数据的访问通过寄存器间直接传递,这样的访问方式比基于栈方式要快很多。测试代码如下:

package t1;public class Hello {public static void main(String[] args) {Hello hello = new Hello();System.out.println(hello.foo(5, 3));}public int foo(int a,int b) {return (a + b) * (a - b);}
}

将以上内容保存为Hello.java。打开命令提示符,执行命令:

$ javac -source 1.6 -target 1.6 Hello.java

:如果使用1.7及以上版本的JDK编译Hello.java,生成Hello.class默认的版本会比较低,使用dx生成dex文件会提示class文件无效。解决方法是强制指定class文件的版本。

继续上面的讨论,执行上面的命令生成Hello.class文件。然后执行命令:

./dx --dex --output=t1/Hello.dex t1/Hello.class

执行上面的命令前,命令行进入到dx工具所在的目录(位于Android SDK的platform-tools目录中),再把t1/Hello.class目录与文件copy到dx工具所在的目录,然后再执行上面的命令生成dex文件。

接下来在Hello.class所在目录使用javap反编译Hello.class查看foo()函数的Java字节码,执行以下命令:

$ javap -c -cp . Hello.class

命令执行后得到如下代码(foo()函数部分):

public int foo(int, int);Code:0: iload_11: iload_22: iadd3: iload_14: iload_25: isub6: imul7: ireturn

下面再使用dexdump(位于Android sdk的platform-tools目录中)查看foo()函数的Dalvik字节码,执行以下命令:

$ ./dexdump -d t1/Hello.dex

命令执行后整理输出结果,可以得到如下代码(foo()函数部分):

000198:                                             |[000198] t1.Hello.foo:(II)I
0001a8: 9000 0304                                   |0000: add-int v0, v3, v4
0001ac: 9101 0304                                   |0002: sub-int v1, v3, v4
0001b0: b210                                        |0004: mul-int/2addr v0, v1
0001b2: 0f00                                        |0005: return v0

查看上面的Java字节码,发现foo()函数一共占用了8个字节,代码中每条指令占用1个字节。比起Java虚拟机字节码,上面的Dalvik字节码显得简洁很多,只有4条指令就完成了下面的操作。

通过上面的分析 可以发现,基于寄存器架构的Dalvik虚拟机与基于栈架构的Java虚拟机相比,由于生成的代码指令减少了,程序执行速度会更快一些。

2. Dalvik虚拟机是如何执行程序的

Android系统由Linux内核,函数库,Android运行时,应用程序框架以及应用程序组成。Dalvik虚拟机属行Android运行时环境,它与一些核心库共同承担Android应用程序的运行工作。

Android系统启动加载完内核后,第一个执行的是init进程,init进程首先要做的是设备的初始化工作,然后读取inic.rc文件并启动系统中的重要外部程序 Zygote。Zygote进程是Android所有进程的孵化器进程,它启动后会首先初始化Dalvik虚拟机,然后启动system_server并进入Zygote模式,通过socket等候命令。当执行一个Android应用程序时,system_server进程通过Binder IPC方式发送命令给Zygote,Zygote收到命令后通过fork自身创建一个Dalvik虚拟机的实例来执行应用程序的入口函数,这样一个程序就启动完成了。

Zygote提供了三种创建进程的方法:

  • fork(),创建一个Zygote进程(这种方式实际不会被调用)

  • forkAndSpecialize(),创建一个非Zygote进程

  • forkSystemServer(),创建一个系统服务进程。

其中,Zygote进程可以再fork()出其他进程,非Zygote进程则不能fork其他进程,而系统服务进程在终止后它的子进程也必终止。当进程fork成功后,执行的工作就交给了Dalvik虚拟机。Dalvik虚拟机首先通过loadClassFromDex()函数完成类的装载工作,每个类被成功解析后都会拥有一个ClassObject类型的数据结构存储在运行时环境中,虚拟机使用gDvm.loadedClasses全局哈希表来存储与查询所有装载进来的类,随后,字节码验证器使用dvmVerifyCodeFlow()函数对装入的代码进行校验,接着虚拟机调用FindCass()函数查找并装载main方法类,随后调用dvmInterpret()函数初始化解释器并执行字节码流。

3. 关于Dalvik虚拟机JIT(即时编译)

JIT(Just-in-time Compilation,即时编译),又称为动态编译,是一种通过在运行时将字节码翻译为机器码的技术,使得程序的执行速度更快。Android2.2版本系统的Dalvik虚拟机引入了JIT技术,官方宣称新版的Dalvik虚拟机比以往执行速度快3~6倍。主流的JIT包含两种字节码编译方式:

  • method方式:以函数或方法为单位进行编译。

  • trace方式:以trace为单位进行编译。

method方式很好理解,那什么是trace方式呢?在函数中一般很少是顺序执行代码的,多数的代码都分成了好几条执行路径,其中函数的有些路径在实际运行过程中是很少被执行的,这部分路径被称为“冷路径”,而执行比较频繁的路径被称为“热路径”。采用传统的method方式会编译整个方法的代码,这会使得在“冷路径”上浪费很多编译时间,并且耗费更多的内存;trace方法编译则能够快速地获取“热路径”代码,使用更短的时间与更少的内存来编译代码。

目前,Dalvik虚拟机默认采用trace方式编译代码,同时也支持采用method方式来编译。

原文:https://my.oschina.net/fhd/blog/365256

Android Dalvik虚拟机之Dalvik虚拟机的特点相关推荐

  1. android -------- java虚拟机和Dalvik虚拟机

    2019独角兽企业重金招聘Python工程师标准>>> java虚拟机 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的.Java虚拟机有自己完善的硬体 ...

  2. Android安全与逆向之Java虚拟机和Dalvik虚拟机的区别

    Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...

  3. (Android)java虚拟机和Dalvik虚拟机的区别

    Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvik虚拟机也第一次进入了人们的视野.它对内存的高效使用,和在低速CPU上表现出的高性能,确实令 ...

  4. Dalvik虚拟机与java虚拟机的区别

    1.Java虚拟机运行的是Java字节码,而Dalvik虚拟机运行的则是其专有的文件格式DEX(Dalvik Executable). 2.Java虚拟机将.java文件编译成字节码文件(.class ...

  5. Java虚拟机和Dalvik虚拟机的区别

    java虚拟机和Dalvik虚拟机的区别 该文章是本人转载的,觉得写的不错,和大家分享一下 Google于2007年底正式发布了Android SDK, 作为 Android系统的重要特性,Dalvi ...

  6. JVM、DVM(Dalvik VM)和ART虚拟机的区别

    JVM.DVM(Dalvik VM)和ART虚拟机的区别 DVM vs JVM 1.共同点: 都是解释执行 都是每个 OS 进程运行一个 VM,并运行一个单独的程序 在较新版本中(Froyo / Su ...

  7. ART/Dalvik,JVM/Dalvik 虚拟机的区别

    从功能上来看,一个高级语言虚拟机主要分为两部分,一个是解释器部分,用来运行高级语言编译生成的ByteCode:还有一部分则是Runtime运行时,用来负责运行时的内存空间开辟.管理等等. JAVA虚拟 ...

  8. java dalvik_Java虚拟机和Dalvik虚拟机的区别

    java虚拟机和Dalvik虚拟机的区别: java虚拟机 Dalvik虚拟机 java虚拟机基于栈. 基于栈的机器必须使用指令来载入和操作栈上数据,所需指令更多更多 dalvik虚拟机是基于寄存器的 ...

  9. Dalvik虚拟机、ART虚拟机

    Dalvik虚拟机 Dalvik虚拟机是Google区Android平台开发的虚拟机,它是Adnroid4.4以前的应用的解释执行器.Dalvik虚拟机并不是Java虚拟机(JVM)的替代器. Dal ...

最新文章

  1. 【Java基础】异常
  2. 第七章、Linux 文件与目录管理
  3. 高性能服务器设计——常用网络服务器设计模型(转载)
  4. 洛谷 P1352 没有上司的舞会
  5. [渝粤教育] 西南科技大学 政府经济学 在线考试复习资料
  6. MediaPlay播放Stream时出现error 38等错误的原因
  7. 你可能不知道的10个Blazor功能
  8. php与bootstrap
  9. 计算机图形学实验一直线-DDA算法
  10. c语言指针实验报告总结,指针(C语言实验报告).doc
  11. SQLException: #22001你知道这个错误码吗
  12. Unity任意轴向朝向某目标实现LookAt功能
  13. DISC四种领导风格
  14. 象棋对战js代码实现
  15. 苹果4s怎么越狱教程_教你苹果手机(iPhone)上怎么装KODI (不用越狱)
  16. 企企通“码上顺”清洗工具 | 让数据更有价值,让业务更出色
  17. Python 生成器(generator)详细总结+示例
  18. 分页和分段有什么区别?
  19. 美国计算机工程专业就业问题,【揭秘】美国就业率排名最高的5个专业 你都知道哪几个呢?...
  20. Navicat 16 中改进了的协同合作

热门文章

  1. 在Debian11 基础上安装 Proxmox VE 7 虚拟化平台
  2. Windows7任务栏下面的图标不见了,去“打开或关闭系统图标”发现它默认关闭了且呈灰色状态,怎么打开??
  3. npx的使用与npm
  4. 【Rust日报】 2020-02-25 KAS GUI 0.3 发布
  5. Chrome扩展全部API
  6. Android SDK 目录详解
  7. android framework资源,android源码framework下添加新资源的方法
  8. vue的router部署从零开始
  9. Eclipse不停build workspace
  10. docker自学系列:docker挂载Nginx配置文件