JAVA语言虚拟机与Dalvik虚拟机对比使用讲解
小标 2018-08-30 来源 : 阅读 870 评论 0

摘要:本文主要向大家介绍了JAVA语言虚拟机与Dalvik虚拟机对比使用讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

本文主要向大家介绍了JAVA语言虚拟机与Dalvik虚拟机对比使用讲解,通过具体的内容向大家展示,希望对大家学习JAVA语言有所帮助。

Dalvik虚拟机的特点

体积小,占用内存空间小

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

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

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

提供了声明周期管理、堆栈管理、线程管理、安全和异常管理以及垃圾回收等功能

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

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

Java虚拟机运行字节码,Dalvik虚拟机运行Dalvik字节码

Dalvik可执行文件体积更小

Java虚拟机基于栈架构,Dalvik虚拟机基于寄存器架构

实例说明Dalvik字节码比Java字节码体积更小

如下代码


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));

    }

}

   

执行如下命令进行编译

 

javac Hello.java

   

然后执行如下命令反编译查看Java字节码

 

javap -c -p -classpath . Hello

   

javap程序位于jdk的bin目录下,说明一下各个参数


-c 对代码进行反汇编

-p 显示所有类和成员

-classpath 查找用户类文件的路径

   

反编译后的字节码 

Compiled from "Hello.java"

public class Hello {

  public Hello();

    Code:

       0: aload_0

       1: invokespecial #1                  // Method java/lang/Object."<init>":()V

       4: return

 

  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

 

  public static void main(java.lang.String[]);

    Code:

       0: new           #2                  // class Hello

       3: dup

       4: invokespecial #3                  // Method "<init>":()V

       7: astore_1

       8: getstatic     #4                  // Field java/lang/System.out:Ljava/io/PrintStream;

      11: aload_1

      12: iconst_5

      13: iconst_3

      14: invokevirtual #5                  // Method foo:(II)I

      17: invokevirtual #6                  // Method java/io/PrintStream.println:(I)V

      20: return

}</init></init>

   

执行如下命令生成class文件对应的dex文件


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

   

注意:dx程序位于sdk目录/build-tools/版本号/,必须将class文件拷贝到该目录再执行上面的命令,不然会出现各种莫名奇妙的问题。

接着执行如下命令看到dex文件对应的Dalvik字节码   

dexdump -d Hello.dex

   

dexdump程序位于sdk目录/build-tools/版本号/,结果如下

Processing 'Hello.dex'...

Opened 'Hello.dex', DEX version '035'

Class #0            -

  Class descriptor  : 'LHello;'

  Access flags      : 0x0001 (PUBLIC)

  Superclass        : 'Ljava/lang/Object;'

  Interfaces        -

  Static fields     -

  Instance fields   -

  Direct methods    -

    #0              : (in LHello;)

      name          : '<init>'

      type          : '()V'

      access        : 0x10001 (PUBLIC CONSTRUCTOR)

      code          -

      registers     : 1

      ins           : 1

      outs          : 1

      insns size    : 4 16-bit code units

00014c:                                        |[00014c] Hello.<init>:()V

00015c: 7010 0400 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0004

000162: 0e00                                   |0003: return-void

      catches       : (none)

      positions     :

        0x0000 line=1

      locals        :

        0x0000 - 0x0004 reg=0 this LHello;

 

    #1              : (in LHello;)

      name          : 'main'

      type          : '([Ljava/lang/String;)V'

      access        : 0x0009 (PUBLIC STATIC)

      code          -

      registers     : 5

      ins           : 1

      outs          : 3

      insns size    : 17 16-bit code units

000164:                                        |[000164] Hello.main:([Ljava/lang/String;)V

000174: 2200 0100                              |0000: new-instance v0, LHello; // type@0001

000178: 7010 0000 0000                         |0002: invoke-direct {v0}, LHello;.<init>:()V // method@0000

00017e: 6201 0000                              |0005: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0000

000182: 1252                                   |0007: const/4 v2, #int 5 // #5

000184: 1233                                   |0008: const/4 v3, #int 3 // #3

000186: 6e30 0100 2003                         |0009: invoke-virtual {v0, v2, v3}, LHello;.foo:(II)I // method@0001

00018c: 0a00                                   |000c: move-result v0

00018e: 6e20 0300 0100                         |000d: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(I)V // method@0003

000194: 0e00                                   |0010: return-void

      catches       : (none)

      positions     :

        0x0000 line=7

        0x0005 line=8

        0x0010 line=9

      locals        :

 

  Virtual methods   -

    #0              : (in LHello;)

      name          : 'foo'

      type          : '(II)I'

      access        : 0x0001 (PUBLIC)

      code          -

      registers     : 5

      ins           : 3

      outs          : 0

      insns size    : 6 16-bit code units

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

      catches       : (none)

      positions     :

        0x0000 line=3

      locals        :

        0x0000 - 0x0006 reg=2 this LHello;

 

  source_file_idx   : 1 (Hello.java)</init></init></init></init>

   

看得眼花缭乱不知所措了,没关系我们挑一部分看即可,我们来单独看看foo()这个函数在Java字节码和Dalvik字节码中的样子。

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

   

Dalvik字节码

   

[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

   

先从直观来看貌似也看不出同样的函数Dalvik指令占用体积小,那就来分析一波。

先看Java字节码

Java虚拟机是基于栈结构的,这里的函数用于求值,也是用到了栈结构,被称为求值栈。

解释一下iload_n指令,i表示加载一个int类型的参数,load表示加载一个局部变量进栈,后面的n表示第几个局部变量,索引值从0开始计数。有人会有疑问,load_0去哪里了,看看最前面我们反编译出的完整的字节码,有0: aload_0,这里是加载了一个引用,将我们的索引值0用掉了,所以此处从1开始。

上面的代码add是加指令,sub是减指令,mul是乘指令。来画个图解释一下。

图1

图2

图3

先把两个参数入栈,遇到add指令从栈顶弹出两个参数想加后将结果入栈,然后再将两个参数入栈,遇到sub指令从栈顶弹出两个参数相减,将结果入栈,然后遇到mul指令再从栈顶弹出两个参数相乘,就是最终的计算结果。

联想一下使用栈配合后缀表达式来做四则混合运算的求值,是不是就可以完整理解上面的代码了。

上面的指令,每条指令占一个字节,所以整个foo()函数占用8个字节。

再来看看Dalvik指令

由于Dalvik虚拟机是基于寄存器的,所以这里的vn都是表示寄存器。

稍微解释一下上面的代码,将v3和v4寄存器的值相加放入v0寄存器,将v3和v4寄存器的值相减放入v1寄存器,将v0和v1寄存器的值相乘放入v0寄存器,最终将v0寄存器的值返回。

其实Dalvik虚拟机在这个过程中也用到了栈,是程序的调用栈,这个栈维护了一个寄存器列表,用于具体的操作求值。

可以看到Dalvik字节码只用了4条指令。

结论:通过对比,发现同样的函数,Dalvik字节码生成指令更少,代码体积更小。

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注编程语言JAVA频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 1 不喜欢 | 0
看完这篇文章有何感觉?已经有1人表态,100%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程