web-dev-qa-db-ja.com

Android:javac vs Dalvik

私の理解では、GoogleはJava MEでJREを使用するためのOracleのライセンスポリシーを好まなかったため、JREを模倣する独自のJVM仕様を使用して書き直しましたが特に、物事をより効率的かつ安全にすることに関しては、動作が少し異なります。

したがって、私の理解が正しければ、javacがJavaソースコードで実行され、「バイナリ」バイトコードにコンパイルされると、準拠したJVMはDalvikとは異なるバイトコードを解釈することを意味します(ある場合)。これは、Dalvikと他の(準拠した)JVMの本質的な違いです。

私がこれまでに言ったことが間違っている場合は、私を訂正することから始めてください!

さて、Androidに独自のコンパイラが付属していて(おそらく)、Javaソースをjavacとは異なる(Dalvik準拠の)方法でコンパイルした場合、コード(Android SDKでコンパイルされていない)はAndroidデバイスでは実行されませんでした:

MySource.Java --> javac --> MySource.class (JRE-compliant) --> JVM --> running Java app
MySource.Java --> Android-compiler --> MySource.class (Dalvik-compliant) --> Dalvik JVM --> running Android app

ただし、javacを使用してAndroidアプリをコンパイルしているようです!?!?したがって、次のようになります。

MySource.Java --> javac --> MySource.class (JRE-compliant) --> JVM --> running Java app
MySource.Java --> javac --> MySource.class (JRE-compliant) --> Dalvik JVM --> running Android app (???)

javacを使用してすべてのソースをバイトコードにコンパイルする場合、Dalvikが一部のタイプのJavaコードを実行できないのはなぜですか?

私は昨日非常によく似た質問をしましたが、技術的には答えられましたが(質問を読み直した後、私は単に十分に具体的ではなかったことがわかりました)、実行を不可能にするDalvikに固有のものを誰も説明できませんでしたJava GoogleGuiceやApacheCamelなどのプロジェクトのコード。 CamelをDalvikで実行するには、Camelのソースを取得してから、「Android SDKでビルド」する必要があると言われましたが、何がわかりませんでした。それは意味または暗示です。

たとえば、Camelを使用すると、次のようになります(簡略化)。

RouteBuilder.Java --> javac --> RouteBuilder.class --> jartool --> camel-context-2.9.jar --> JVM --> running Camel ESB
RouteBuilder.Java --> javac --> RouteBuilder.class --> jartool --> camel-context-2.9.jar --> Dalvik JVM --> doesn't work !!! (???)

明らかに、Dalvik JVM内で、特定のタイプのJavaコードの実行を妨げる何かが起こっています。 Dalvik JVMに「フィード」されたときに実行されないJavaコードのタイプを理解しようとしています。

編集:の前にCamel 3.0はAndroidで実行されます!」私は知っています-私の質問ではありません!

25
IAmYourFaja
I'm trying to understand what types of Java code will not run when "fed" into the Dalvik JVM.

Dalvik JVMは、次の点で他のJVMとは異なります:

  • アプリケーションのバイナリを格納するために特別なDEX形式を使用しますが、標準のJava仮想マシンで使用されるJARおよびPack200形式です。DEXの結果はJARよりも小さいと主張しています。Pack200を使用できると思います。同じ成功ですが、彼らはこの側面で独自の道を進むことにしました

  • Dalvik JVMは、複数のJVMプロセスを同時に実行するために最適化されました

  • Dalvik JVMは、実行を高速化し、バイナリサイズを削減することを目的として、他のJVMのレジスタベースのアーキテクチャとスタックベースのアーキテクチャを使用します。

  • 独自の命令セット(標準のJVMバイトコードではない)を使用します

  • (必要に応じて)単一のJVMプロセス内で複数の独立したAndroidアプリケーションを実行できます)

  • アプリケーションの実行は、複数のDalvikJVMプロセスに「自然に」及ぶ可能性があります。これをサポートするために、次のように追加します。

    • ParcelクラスとParcelableクラスに基づく特別なオブジェクトシリアル化メカニズム。機能的には、標準と同じ目的を果たしますJavaシリアライズ可能ですが、データフットプリントが小さくなり、クラスのバージョンの違いに対して寛容になる可能性があります

    • 特別なAndroid Androidインターフェイス定義言語(AIDL)に基づくプロセス間呼び出し(IPC)を実行する方法

  • Android 2.2 Dalvik JVMはJITコンパイルをサポートしていなかったため、Androidアプリケーションのパフォーマンスに悪影響を及ぼしました。2.2で追加すると、頻繁に使用されるアプリケーションの実行速度が大幅に向上します。

28
user370305

私がこれまでに言ったことが間違っている場合は、私を訂正することから始めてください!

うーん、まあ...

  • Dalvik VMは、モバイル環境のJava VM、特にコピーオンライトの積極的な使用よりも技術的な利点があります。メモリ共有を書き込むため、VMおよび標準クラスライブラリ全体がすべてのAndroid SDKアプリプロセス間で共有され、プロセスごとの正味のメモリフットプリントが削減されます。user370305を参照してください。詳細については、回答(これをまとめている間に投稿されました)。

  • javacのバイトコードは、Androidアプリケーションビルドプロセスの一部として、Dalvikバイトコードにクロスコンパイルされます。Java VMは、/dev/randomの出力を実行できる以上にDalvikバイトコードを実行できません。同様に、Dalvik VMは実行できませんJavaバイトコード。

これが私のブログ投稿です 約2年前からの追加のポイントになります。

Javacを使用してすべてのソースをバイトコードにコンパイルする場合、Dalvikが一部のタイプのJavaコードを実行できないのはなぜですか?

javacバイトコード出力はクロスコンパイルされているためです。クロスコンパイラ(dx)は、非常に特殊なjavac出力を処理します。つまり、従来のjavac(Java.Sunから取得したもの)で動作します。 .com)およびOpenJDK for Java 1.5および1.6、代替コンパイラ(GCJなど)では機能せず、少なくともJava 7。

googleGuiceやApacheCamelなどのプロジェクトからJavaコードを実行できなくなるのは、Dalvikに固有のものであるということを誰も説明できませんでした。

個人的には、Google Guiceを使用したことはありませんが、 Roboguice Androidで動作します。私はあなたの質問の前にApacheCamelについて聞いたことがなく、それがJava Perlのポートではないことを見つけるのにかなり混乱しています。:-)

クロスコンパイラーは実行時ではなくコンパイル時にのみ使用可能であるため、ランタイムJVMバイトコード生成を実行するツールはAndroidでは機能しません。また、ランタイムJVMバイトコード生成ツールで使用される手法と、JVMにそのバイトコードを実行させる方法に慣れていないため、Androidに同等のフックが存在するかどうかはわかりません。 Dalvikは、Dalvikバイトコードの任意のチャンクを実行します。

ただし、問題のある「GoogleGuiceやApacheCamelなどのプロジェクトのJavaコード」を正確に指定することを拒否し、これらのプロジェクトに精通していないため、これ以上コメントすることは困難です。

24
CommonsWare

Android公式ドキュメントからのこの写真は、Android APKのビルドプロセスを示しています。これは、Javaバイトコードとdalvik実行可能ファイル。 enter image description here

ここでは、いくつかの違いを示す例を示します。

Hello.Java

import Java.io.*;
public class Hello {
    public static void main(String[] args) {
        System.out.println("hello world!!!!");
    }
}

javacを使用してHello.JavaをJavaバイトコードHello.classにコンパイルします

$ javac Hello.Java

次に、dxツールをAndroid sdk convert Java bytecode Hello.class to Hello.dexから

$ $Android_SDK_ROOT/build-tools/21.1.2/dx --dex --output=Hello.dex Hello.class

その後、adbを使用してHello.classHello.dexをAndroidデバイスまたはエミュレーターに配置します。

$ adb Push Hello.class /data/local/tmp/
$ adb Push Hello.dex /data/local/tmp/

adb Shellを使用してAndroidデバイスのシェル環境に入ります。次に、コマンド/system/bin/dalvikvmを使用して、単純なJavaプログラムを実行します。 Hello.classHello.dexを作成しました

$ dalvikvm -Djava.class.path=./Hello.class Hello
Java.lang.NoClassDefFoundError: Hello
    at dalvik.system.NativeStart.main(Native Method)
Caused by: Java.lang.ClassNotFoundException: Didn't find class "Hello" on path: ./Hello.class
    at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.Java:65)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:501)
    at Java.lang.ClassLoader.loadClass(ClassLoader.Java:461)
    ... 1 mor
$ dalvikvm -Djava.class.path=./Hello.dex Hello   
hello world!!!!

上記の例では、JavaバイトコードHello.classdalvikvm苦情エラーを使用する場合、クラスをdalvik実行可能ファイルHello.dexに変更すると、正しく実行されます。

11
alijandro