Java 虚拟机与 Dalvik 虚拟机的区别
简述JVM基于栈架构。DVM 虚拟机基于寄存器架构(意指由一个指令之输出或输入可以直接索引到的寄存器组群)。因为实现架构的差异,则DVM对指令的响应要快于 JVM。代码实践public class Hello{public int foo(int a,int b){return (a+b)*(a-b);}public static vo
简述
JVM基于栈架构。
DVM 虚拟机基于寄存器架构(意指由一个指令之输出或输入可以直接索引到的寄存器组群)。
因为实现架构的差异,则DVM对指令的响应要快于 JVM。
代码实践
public class Hello{
public int foo(int a,int b)
{
return (a+b)*(a-b);
}
public static void main(String[] args){
Hello hello = new Hello();
System.out.println(hello.foo(5,3));
}
}
编写以上代码保存为Hello.java
。打开命令提示符,执行命令javac Hello.java
编译生成Hello.class
文件。
然后执行命令dx --dex --out=Hello.dex Hello.class
。
不幸的是,它抛出异常了,看来是 JDK
的版本问题造成的。
UNEXPECTED TOP-LEVEL EXCEPTION:
java.lang.RuntimeException: Exception parsing classes
at com.android.dx.command.dexer.Main.processClass(Main.java:752)
at com.android.dx.command.dexer.Main.processFileBytes(Main.java:718)
at com.android.dx.command.dexer.Main.access$1200(Main.java:85)
at com.android.dx.command.dexer.Main$FileBytesConsumer.processFileBytes(Main.java:1645)
at com.android.dx.cf.direct.ClassPathOpener.processOne(ClassPathOpener.java:170)
at com.android.dx.cf.direct.ClassPathOpener.process(ClassPathOpener.java:144)
at com.android.dx.command.dexer.Main.processOne(Main.java:672)
at com.android.dx.command.dexer.Main.processAllFiles(Main.java:574)
at com.android.dx.command.dexer.Main.runMonoDex(Main.java:311)
at com.android.dx.command.dexer.Main.run(Main.java:277)
at com.android.dx.command.dexer.Main.main(Main.java:245)
at com.android.dx.command.Main.main(Main.java:106)
Caused by: com.android.dx.cf.iface.ParseException: bad class file magic (cafebabe) or version (0034.0000)
at com.android.dx.cf.direct.DirectClassFile.parse0(DirectClassFile.java:472)
at com.android.dx.cf.direct.DirectClassFile.parse(DirectClassFile.java:406)
at com.android.dx.cf.direct.DirectClassFile.parseToInterfacesIfNecessary(DirectClassFile.java:388)
at com.android.dx.cf.direct.DirectClassFile.getMagic(DirectClassFile.java:251)
at com.android.dx.command.dexer.Main.parseClass(Main.java:764)
at com.android.dx.command.dexer.Main.access$1500(Main.java:85)
at com.android.dx.command.dexer.Main$ClassParserTask.call(Main.java:1684)
at com.android.dx.command.dexer.Main.processClass(Main.java:749)
... 11 more
1 error; aborting
$ java -version
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
这里需要把JDK
版本指定为1.6
重新编译Hello.class
。(为什么要更换成1.6
?)
$ javac -source 1.6 -target 1.6 Hello.java
然后执行命令dx --dex --out=Hello.dex Hello.class
。此刻,已经顺利生成了Hello.dex
。
接下来执行
javap -c -classpath . Hello
命令执行后得到如下代码,针对foo()
函数:
// Java 字节码
public int foo(int, int);
Code:
0: iload_1
1: iload_2
2: iadd
3: iload_1
4: iload_2
5: isub
6: imul
7: ireturn
接着执行命令:dexdump
可在 sdk/build-tools/
目录下找到。
dexdump -d Hello.dex
生成 Dalvik
字节码如下,针对foo()
函数:
// Dalvik 字节码
000198: |[000198] 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 字节码,共8条指令(每条指令占一个字节,并且这些指令都没有参数)。
Q:那么这些指令是如何存取数据的呢?
A:Java 指令集被称为零地址形式的指令集,所谓零地址形式,是指指令的源参数与目标参数都是隐含的,它通过 Java 虚拟机中提供的一种数据结构“求值栈”来传递的。
结合代码来理解理论知识:
完整指令 | PC | 类型 | 指令 | 连接符 | 局部变量 | 步骤说明 |
---|---|---|---|---|---|---|
0:iload_1 | 0 | i (int类型) | load (将局部变量存入 Java 栈) | - | 1 (局部变量索引) | 将第2个 int 类型的局部变量进栈 |
1:iload_2 | 1 | i | load | - | 2 | 将第3个 int 类型的局部变量进栈 |
2:iadd | 2 | i | add | 从栈顶弹出两个 int 类型值,将值相加,然后把结果压回栈顶 | ||
3:iload_1 | 3 | i | load | - | 1 | 将第2个 int 类型的局部变量进栈 |
4:iload_2 | 4 | i | load | - | 2 | 将第3个 int 类型的局部变量进栈 |
5:isub | 5 | i | sub | 从栈顶弹出两个 int 类型值,将值相减,然后把结果压回栈顶 | ||
6:imul | 6 | i | mul | 从栈顶弹出两个 int 类型值,将值相乘,然后把结果压回栈顶 | ||
7:ireturn | 7 | i | return | 返回一个 int 值 |
所以与之类似的还有lload
,dload
,fload
… 更多信息查看:Java字节码。
Java 虚拟机与 Dalvik 虚拟机的区别
相比 Java 字节码,我们依旧对照代码分析 Dalvik 字节码。
比起 JVM字节码显然 Dalvik字节码更简洁,只有4条指令就完成了上面的工作。
第一条指令 add-int 将 v3与 v4寄存器的值相加,然后保存到 v0寄存器。整个指令的操作中使用到了三个参数,v3、v4分别代表 foo()函数的入参。
第二条指令 sub-int 将 v3减去 v4的值保存到 v1寄存器。
第三条指令 mul-int/2addr 将 v0乘以 v1保存到 v0寄存器。
第四条指令返回 v0寄存器的值。
Dalvik虚拟机运行时同样为每个线程维护一个 PC计数器与调用栈,与 Java 虚拟机不同的是,这个调用栈维护一份寄存器列表,寄存器的数量在方法结构体的 registers 字段中给出,Dalvik 迅疾会根据这个值来创建一份虚拟的寄存器列表。
通过分析得出,基于寄存器架构的 Dalvik 虚拟机与基于栈架构的 Java 虚拟机相比,由于生产的代码指令减少了,程序执行的速度会更快一些。
更多推荐
所有评论(0)