Dalvik虚拟机学习
一、Dalvik虚拟机特点:
1)体积小,占用内存小
2)使用DEX可执行文件,执行速度快
3)常量池32位,寻址类方法名、字段、常量更快
4)基于寄存器,并拥有完整的指令系统
5)提供对象生命周期、堆栈、线程、安全、异常、垃圾回收等重要功能
6)每个Android程序对应一个Dalvik虚拟机实例
与JAVA虚拟机的区别
1)Dalvik字节码与JAVA字节码的不同
2)dx工具对class文件中方法签名、常量池等进行压缩精简
实验
构造这样的代码:
public class Java_Dalvik_Byte_Code_Compare{
public int foo(int a, int b){
return (a+b)*(a-b);
}
public static void main(String[] args) {
Java_Dalvik_Byte_Code_Compare first = new Java_Dalvik_Byte_Code_Compare();
System.out.println(first.foo(, ));
}
}
- 使用
编译生成class文件javac xxx.java
- 使用
生成dex文件dx --dex --output=xxx.dex xxx.class
- 使用
反编译Java字节码javap -c xxx.class
Compiled from "Java_Dalvik_Byte_Code_Compare.java" public class Java_Dalvik_Byte_Code_Compare { public Java_Dalvik_Byte_Code_Compare(); Code: : aload_0 : invokespecial #1 // Method java/lang/Object."<init>":()V : return public int foo(int, int); Code: : iload_1 : iload_2 : iadd : iload_1 : iload_2 : isub : imul : ireturn public static void main(java.lang.String[]); Code: : new #2 // class Java_Dalvik_Byte_Code_Compare : dup : invokespecial #3 // Method "<init>":()V : astore_1 : getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream; : aload_1 : iconst_5 : iconst_3 : invokevirtual #5 // Method foo:(II)I : invokevirtual #6 // Method java/io/PrintStream.println:(I)V : return }
- 使用
反编译dex文件dexdump.exe -d xxx.dex
Processing '.\Java_Dalvik_Byte_Code_Compare.dex'... Opened '.\Java_Dalvik_Byte_Code_Compare.dex', DEX version '035' Class #0 - Class descriptor : 'LJava_Dalvik_Byte_Code_Compare;' Access flags : x0001 (PUBLIC) Superclass : 'Ljava/lang/Object;' Interfaces - Static fields - Instance fields - Direct methods - #0 : (in LJava_Dalvik_Byte_Code_Compare;) name : '<init>' type : '()V' access : x10001 (PUBLIC CONSTRUCTOR) code - registers : ins : outs : insns size : -bit code units c: |[c] Java_Dalvik_Byte_Code_Compare.<init>:()V c: |: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // [email protected] : e00 |: return-void catches : (none) positions : x0000 line= locals : x0000 - x0004 reg= this LJava_Dalvik_Byte_Code_Compare; #1 : (in LJava_Dalvik_Byte_Code_Compare;) name : 'main' type : '([Ljava/lang/String;)V' access : x0009 (PUBLIC STATIC) code - registers : ins : outs : insns size : -bit code units : |[] Java_Dalvik_Byte_Code_Compare.main:([Ljava/lang/String;)V : |: new-instance v0, LJava_Dalvik_Byte_Code_Compare; // [email protected] : |: invoke-direct {v0}, LJava_Dalvik_Byte_Code_Compare;.<init>:()V // [email protected] e: |: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // [email protected] : |: const/ v2, #int // #5 : |: const/ v3, #int // #3 : e30 |: invoke-virtual {v0, v2, v3}, LJava_Dalvik_Byte_Code_Compare;.foo:(II)I // [email protected] c: a00 |c: move-result v0 e: e20 |d: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(I)V // [email protected] : e00 |: return-void catches : (none) positions : x0000 line= x0005 line= x0010 line= locals : Virtual methods - #0 : (in LJava_Dalvik_Byte_Code_Compare;) name : 'foo' type : '(II)I' access : x0001 (PUBLIC) code - registers : ins : outs : insns size : -bit code units : |[] Java_Dalvik_Byte_Code_Compare.foo:(II)I a8: |: add-int v0, v3, v4 ac: |: sub-int v1, v3, v4 b0: b210 |: mul-int/addr v0, v1 b2: f00 |: return v0 catches : (none) positions : x0000 line= locals : x0000 - x0006 reg= this LJava_Dalvik_Byte_Code_Compare; source_file_idx : (Java_Dalvik_Byte_Code_Compare.java)
- 使用
对比两边foo()函数的代码,可以很明显看出基于寄存器的Dalvik虚拟机执行步骤相较于基于栈的JVM精简了很多。
另外注意,Dalvik反编译的汇编中参数顺序与入栈顺序一致。
Dalvik虚拟机执行程序流程
Zygote
- 系统启动
- init进程运行
- 读取inic.rc并启动重要孵化器进程Zygote
- Zygote初始化Dalvik虚拟机
- 启动system_server并进入Zygote模式,通过socket等待命令
- 当执行应用程序时,system_server通过socket通知Zygote,Zygote立刻fork自身创建一个Dalvik虚拟机实例来执行目标程序的入口函数。
Dalvik
- Dalvik虚拟机运行loadClassFromDec()完成类装载,类数据结构为ClassObject
- 使用gDvm.loadedClasses全局哈希表来存储/查询装载进来的类
- 字节码验证器使用dvmVerifyCodeFlow()函数对载入的代码进行校验
- 调用FindClass()函数查找并装载main方法类
- 调用dvmInterpret()初始化解释器并执行字节码