Android:javac vs Dalvik

我的理解是,Google不喜欢Oracle在Java ME中使用JRE的许可策略,因此它只是使用自己的JVM规范来重写它,而JRE规范模仿了JRE,但行为有点不同,特别是在提高效率和更安全。

所以,如果我的理解是正确的,这意味着当javac运行在一些Java源代码上并编译成“二进制”byetcode时,兼容的JVM将解释与Dalvik不同的字节码(在某些情况下)。 这是Dalvik和其他(兼容)JVM之间的固有区别。

如果我迄今为止所说的话是不正确的,请首先纠正我!

现在,如果Android带有自己的编译器(可能),并以不同的(Dalvik兼容的)方式编译Java源代码,那么我可以理解一些代码(不是用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无法运行某些types的Java代码?

我昨天问了一个非常类似的问题,虽然它在技术上得到了答案(在重新阅读我的问题之后,我看到我没有足够具体),没有人能够解释Dalvik固有的特性使得无法运行Java代码从谷歌Guice或Apache骆驼项目。 有人告诉我,为了让骆驼在Dalvik上运行,我必须得到Camel的源代码,然后才能用“Android SDK”来构build,但我无法弄清楚这是什么意思或暗示。

例如,骆驼,你有这个(简化):

 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内部正在发生一些阻止它运行某些types的Java代码的事情。 我试图了解什么types的Java代码在“喂”到Dalvik JVM时不会运行。

编辑:在之前“, 但骆驼3.0将在Android上运行! ”我知道 – 不是我的问题!

Solutions Collecting From Web of "Android:javac vs Dalvik"

 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格式。 Google声称DEX的结果比JAR小。 我认为他们可以用同样的成功使用Pack200,但他们决定在这方面走自己的路

  • Dalvik JVM针对同时运行多个JVM进程进行了优化

  • Dalvik JVM使用基于寄存器的体系结构与其他JVM的基于堆栈的体系结构,旨在加速执行并减less二进制大小

  • 它使用自己的指令集(不是标准的JVM字节码)

  • 可以在单个JVM进程中运行(如果需要的话)几个独立的Android应用程序

  • 应用程序的执行可以“自然”跨越多个Dalvik JVM进程。 为了支持这个,它增加了:

    • 基于Parcel和Parcelable类的特殊对象序列化机制。 在function上,它与标准的Java Serializable具有相同的用途,但是会导致较小的数据占用空间,并且可能会对类的版本差异更为宽松

    • 基于Android接口定义语言(AIDL)的特殊Android方式执行进程间调用(IPC)

  • 直到Android 2.2 Dalvik JVM不支持对Android应用程序性能产生负面影响的JIT编译。 在2.2中添加它可以显着提高常用应用程序的执行速度

如果我迄今为止所说的话是不正确的,请首先纠正我!

嗯,好吧…

  • Dalvik VM与移动环境的Java VM相比具有技术优势,尤其是积极使用写入时复制内存共享,因此整个VM和标准类库在所有Android SDK应用程序进程之间共享,从而减less了每进程的networking内存占用。 看到user370305的答案(张贴时,我包装了这一点)更多。

  • 作为Android应用程序构build过程的一部分,来自javac的字节码被交叉编译成Dalvik字节码。 Java VM不能执行Dalvik字节码,而不能执行/dev/random的输出; 同样,Dalvik虚拟机不能执行Java字节码。

这里是大约两年前我的一篇博客文章 。

如果使用javac将所有源代码编译为字节码,那么为什么Dalvik无法运行某些types的Java代码?

因为javac字节码输出是交叉编译的。 交叉编译器( dx )处理javac输出的一个非常具体的味道,这意味着,虽然它与经典的javac (你从java.sun.com得到的)和OpenJDK for Java 1.5和1.6一起工作,但它不能工作使用其他编译器(例如GCJ),并且至less不能与Java 7中的任何新的字节码一起工作。

没有人能够解释Dalvik固有的东西,使得从Google Guice或Apache Camel这样的项目运行Java代码变得不可能

就个人而言,我从来没有使用谷歌Guice,虽然Roboguice在Android上工作。 在您提出问题之前,我从来没有听说过Apache Camel,并且很困惑地发现它不是Perl的Java端口。 🙂

任何执行运行时JVM字节码生成的工具都不能在Android上工作,只是因为交叉编译器只能在编译时使用,而不能在运行时使用。 此外,我不熟悉运行时JVM字节码生成工具所使用的技术以及如何让JVM执行该字节码,因此我不知道Android中是否存在等价的钩子,让Dalvik运行Dalvik字节码的任意块。

但是,由于您拒绝明确指出“Google Guice或Apache Camel等项目中的Java代码”是否存在问题,而且由于我对这些项目并不熟悉,所以很难进一步评论。

这个来自Android官方文档的图片说明了Android APK的构build过程,它有助于理解java字节码和dalvik可执行文件的区别。 在这里输入图像说明

这里我举一个例子来说明一些差异。

Hello.java

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

使用javacHello.java编译为java字节码Hello.class

 $ javac Hello.java 

然后使用dx工具从android sdk转换java字节码Hello.classHello.dex

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

之后,使用adbHello.classHello.dex到Android设备或模拟器。

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

使用adb shell进入Android设备的shell环境。 然后使用命令/system/bin/dalvikvm来执行我们刚刚创build的Hello.classHello.dex的简单java程序

 $ 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 ,它会正常运行。