Dalvik虚拟机的特点:

  • 体积小,占用内存空间小
  • 专有的DEX 可执行文件格式,体积更小,执行速度更快
  • 常量池采用32位索引值,寻址类方法名、字段名、常量更快
  • 基于寄存器架构,拥有一套完整的指令系统
  • 提供了对象生命周期管理、堆栈管理、线程管理、安全和异常管理以及垃圾回收等重要功能
  • 所有的Android程序都运行在Android系统进程里,每个进程对应着一dalvik虚拟机实例


Dalvik虚拟机与Java虚拟机的区别:


1、Java虚拟机运行的是Java字节码,Dalvik虚拟机运行的是Dalvik字节码

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

而Dalvik虚拟机运行的是Dalvik字节码,它由Java字节码转换而来,并被打包到一个DEX(Dalvik Executable)可执行文件中,Dalvik虚拟机通过解释DEX文件来执行这些字节码。


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

Android SDK中有一个叫dx的工具负责将Java字节码转换为Dalvik字节码,它将Java类文件重新排列,消除文件中出现的冗余信息,避免虚拟机在初始化时出现重复的加载与解析过程。




3、Java虚拟机与Dalvik虚拟机架构不同

Java虚拟机基于栈架构,程序在运行虚拟机时需要频繁的从栈上读取或写入数据;

而Dalvik虚拟机基于寄存器架构,数据的访问通过寄存器间直接传递。


实例证明:


测试代码:(Hello.java)


public class Hello{

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

}


使用编译命令生成class文件

javac Hello.java


先来分析Java虚拟机中的存储和运行情况:

使用Javap命令反编译class文件,查看class文件中的foo函数的字节码


javap -c -classpath . Hello

关于参数作用的解释:




运行结果:




图中黄色框框内的为foo函数的字节码,代码中每条指令占用1个字节,一共占用了8个字节,并且这些指令都没有参数。

在Java虚拟机中,指令的源参数和目标参数都是隐含的,称为零地址形式。

对于Java程序,每个线程在执行时都有一个PC计数器和一个Java栈。

PC计数器只对当前方法有效,Java虚拟机通过PC计数器的值来取指令执行。

Java栈用于记录Java方法调用的“活动记录”,以帧为单位保存线程的运行状态,每调用一个方法就会分配一个新的栈帧压入Java栈,没从一个方法返回则弹出并撤销相应的栈帧,每个栈帧包括局部变量区、求值栈和其他一些信息。方法的参数按从左到右的顺序保存在局部变量区开头的几个slot中。

对于foo()函数,图示如下:




由于每条指令占用一个字节的空间,foo()函数的Java字节码左边的偏移量就是程序执行到每一行代码时PC的值,Java虚拟机最多只支持0xff条指令。

第一条指令iload_1可分为两部分:

第一部分为下划线左边的iload,iload是JVM指令集中的一条指令,i是指令前缀,表示操作类型为int类型,load表示将局部变量存入Java栈,类似的有lload、fload、dload,分别表示将long、float、double类型的数据进栈;

第二部分为下划线右边的数字,表示要操作具体两个局部变量,索引值从0开始计数;

iload_1表示将第二个int类型的局部变量进栈,即foo()函数的第一个参数

下面的几条指令同理。

第8条ireturn函数返回一个int值。


---------------------------转角分割线---------------------------------------


再来分析Dalvik虚拟机中的情况:

首先需要把class文件转换成dex文件,需要用到的命令为


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

关于参数的解释为:




可是执行的时候问题出现了,总是报Hello.class找不到的错误。。。发火

尝试了N次,大概共有三种方法,但是我只成功了两种,第三种还有问题没有解决。。。抓狂

方法一:将Hello.class文件与dx放在同一目录下,dx在SDK里面的build-tools文件夹下


命令同上


方法二:在help里面的第二个黄色框框后面,还有一个directory选项,所以将Hello.class替换为它所在的目录


这两种方法所生成的hex文件都在dx的同一目录下


dx --dex --output=Hello.dex e:/security/3


方法三:我用的是JDK1.7,貌似是版本太高了,所以要强制使用1.6重新编译

但是我不知道咋回事老错。。。。再见





总之现在得到了hex文件。。呵呵呵

现在要反编译Hello.hex文件得到Dalvik字节码,命令为


dexdump -d Hello.hex

关于参数的解释:




得到的结果为(黄色框框的部分)




有点不忍直视。。这一块的字节码为:


|[000198] Hello.foo:(II)I
|0000: add-int v0, v3, v4
|0002: sub-int v1, v3, v4
|0004: mul-int/2addr v0, v1
|0005: return v0

v3、v4代表函数的两个参数

第一条指令为V3、V4相加存入V0寄存器,以下同理。

仅用了四条指令....当然执行速度更快了。


Dalvik虚拟机运行时同样回味每个线程维护一个PC计数器和调用栈,至少这个调用栈维护一份寄存器列表,寄存器的数量在方法结构体的registers字段中给出,Dalvik虚拟机会根据这个值来创建一份虚拟的寄存器列表。

状态图如下:





---------------------------疲惫的分割线-------------------------------------







Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐