Java仮想マシンとDalvik仮想マシンの違い

14834 ワード

簡単に述べる
JVMはスタックアーキテクチャに基づく。DVM仮想マシンは、1つの命令の出力または入力によって直接的にインデックスされ得るレジスタ群を意味するレジスタアーキテクチャに基づく。アーキテクチャの違いを達成するため、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に変えましたか?)
$ javac -source 1.6 -target 1.6 Hello.java 
その後、コマンド1.6が実行される。現在、順調にdx --dex --out=Hello.dex Hello.classが生成されました。次に実行します
    javap -c -classpath . Hello
コマンド実行後、Hello.dex関数に対して以下のコードが得られます。
    // 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
次にコマンドを実行します。foo()dexdumpディレクトリの下で見つけることができます。
dexdump -d Hello.dex
sdk/build-tools/バイトコードを生成すると、Dalvikの関数として以下のようになる。
    // 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つの命令があります。各コマンドは1バイトを占めています。これらのコマンドはパラメータがありません。Q:これらのコマンドはどのようにデータにアクセスしますか?A:Javaコマンドセットは、ゼロアドレス形式のコマンドセットと呼ばれています。ゼロアドレス形式とは、命令のソースパラメータとターゲットパラメータが暗黙的であり、Java仮想マシンで提供されるデータ構造「シークレットスタック」を通じて伝達されます。コードを結合して理論知識を理解する:
完全コマンド
PC
タイプ
コマンド
コネクタ
ローカル変数
ステップ説明
0:iload_1
0
i(intタイプ)
ロード(ローカル変数をJavaスタックに保存)
を選択します。
1(局所変数インデックス)
2番目のintタイプの局所変数をスタックに入れます。
1:iload_2
1
i
ロード
を選択します。
2
3番目のintタイプの局所変数をスタックに入れます。
2:iadd
2
i
add
スタックの一番上から二つのintタイプの値を引き出して、値を加算して、結果をスタックの一番上に戻します。
3:iload_1
3
i
ロード
を選択します。
1
2番目のintタイプの局所変数をスタックに入れます。
4:iload_2
4
i
ロード
を選択します。
2
3番目のintタイプの局所変数をスタックに入れます。
5:isub
5
i
sub
スタックの一番上から2つのintタイプの値をイジェクトして、値を減じて、結果をスタックの一番上に戻します。
6:imul
6
i
むじんl
スタックの一番上から2つのintタイプの値をイジェクトし、値を乗算し、結果をスタックの一番上に押し戻す。
7:ireturn
7
i
return
ポイントを返します。
したがって、これと同様に、foo()lloaddload…より多くの情報は、Javaバイトコードを参照してください。
Java仮想マシンとDalvik仮想マシンの違いはJavaバイトコードに比べて、コードに合わせてDalvikバイトコードを分析しています。
JVMバイトコードより明らかにDalvikバイトコードの方が簡潔で、4つの命令だけが上記の作業を完了しました。
第1のコマンドadd-intはv 3とv 4レジスタの値を加算してv 0レジスタに保存します。命令全体の動作には三つのパラメータが使用され、v 3、v 4はそれぞれfoo()関数の入力を表しています。第二条命令sub-inntはv 3からv 4を減算した値をv 1レジスタに保存する。第3条コマンドmull-innt/2 addrは、v 0をv 1に掛けてv 0レジスタに保存する。第4のコマンドは、v 0レジスタの値を返します。
Dalvik仮想マシンが動作する時も、同じスレッドのために1つのPCカウンタとコールスタックを維持し、Java仮想マシンとは違って、このコールスタックはレジスタリストを維持し、レジスタの数は、メソッド構造体のregisterフィールドに与えられ、Dalvik迅疾はこの値に基づいて仮想レジスタリストを作成します。
解析により、レジスタアーキテクチャに基づくDalvik仮想マシンは、スタックアーキテクチャに基づくJava仮想マシンに比べて、製造されたコード命令が減少したため、プログラム実行の速度がより速くなることがわかった。