Dalvik可执行格式

知道学的是啥,有啥用,在平时生活中扮演什么角色时,就会主动想去学了。

虽然Android系统采用Java语言来开发应用程序,但Android程序却不是运行在传统的Java虚拟机上的。

可能为了解决与Oracle版本问题,或者是Java虚拟机在设备上卡顿问题,Google对Android系统设计了专属的虚拟机,从Android4.4开始引入了ART(Android RunTime)虚拟机,将由JIT(实时编译)执行的Dalvik虚拟机切换为由AOT编译的ART,为了向下兼容,ART也支持Dalvik格式和字节码的支持。Dalvik虚拟机目前仍然是需要重点研究的对象。这就解释了什么是Dalvik,以及为什么我要学Dalvik汇编语言知识了。

一、Dalvik虚拟机的特点

  • 1、体积小,占用内存空间小

  • 2、专有的DEX(Dalvik Executable)可执行文件格式,体积小,执行速度快。

  • 3、常量池采用32位索引值,对类方法名、字段名、常亮的寻址速度快。

  • 4、基于寄存器架构,同时拥有一套完整的指令系统(Dalvik汇编)

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

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

对以上内容会有一一对应的解释。

二、Dalvik虚拟机与Java虚拟机的区别

1、运行的字节码不同

Java虚拟机运行的是Java字节码,Dalvik虚拟机运行的是Dalvik字节码(可以理解为汇编)。

传统的Java程序经过编译,生成Java字节码并保存在class文件中,Java虚拟机通过解码Class文件内容运行程序;

Dalvik虚拟机运行的Dalvik字节码是由Java字节码转换而来,并被打包到一个DEX可执行文件中(为什么使用JEB反编译DEX文件,就是通过DEX还原源JAVA代码),Dalvik虚拟机通过解释DEX文件来执行这些字节码。

2、Dalvik可执行文件的体积更小

为什么Dalvik可执行文件dex体积更小?
在Android SDK中,将Java字节码转换为Dalvik字节码的工具是"dx"。dx能够重新排列Java类文件,消除在类文件中的冗余信息,避免重复加载和解析。

原理是这样子的:
Java类中通常有多个方法签名,如果它被调用或者继承,这些签名和方法也会被继承在调用方,所以大量的类包含同样的签名和字符串常量造成冗余。DX把这些常量统一存放在"常量池"中,一个常量只出现一次,供所有类使用,所以DEX文件体积更小。

3、虚拟机架构不同

Java虚拟机基于栈架构,运行时指令频繁入栈和出栈,占用大量CPU时间,对于资源有限的设备资源比较吃紧。

而Dalvik是基于寄存器架构的,指令发送给寄存器。总所周知,直接操作寄存器的汇编语言执行速度是最快的。因为是搞逆向的,甭指望直接搞到源码,所以要会汇编,反推源代码逻辑,所以要学Dalvik汇编指令。

4、虚拟机执行流程

对所要研究的东西研究更深入一些,知其然知其所以然,遇到问题就不会慌。

Android系统架构图。
Dalvik可执行格式
所有的与硬件的驱动都基于Linux内核,"所有皆文件"的linux设计理念,方便于其他系统集成。

Libray通用库、上层框架和应用层暂没研究。

着重Dalvik虚拟机。

Dalvik属于Android运行时环境。
Dalvik可执行格式
Zygote是所有进程的孵化器,应用程序通过system_server将指令发给Zygote,Zygote为其分配一个单独的进程,并由Dalvik执行。

Dalvik通过loadClassFromDex()装载类。类被解析后变成ClassObject类型的数据结构存储,虚拟机采用gDvm.loadedClass全局散列表(类似map)存储和查询。

字节码验证器使用dvmVerifyCodeFlow()函数对装入的代码进行校验,虚拟机调用FindClass()函数查找并找到main()方法类。最后调用dvmInterpret()函数来初始化解释器并执行字节流。

5、虚拟机执行方式

即时编译。参考C++和C编译的感人速度,就知道虚拟机的即时编译多么重要。尤其C++是将所有的代码编成字节码后再运行,即时编译是在运行时编译字节码,使程序的执行速度加快。