Android: javac vs Dalvik

2022-09-01 13:48:24

我的理解是,谷歌不喜欢Oracle在Java ME中使用JRE的许可政策,所以它只是使用自己的JVM规范重写了它,该规范模仿JRE,但行为略有不同,特别是在使事情变得更高效,更安全时。

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

如果到目前为止我所说的任何话都是不正确的,请从纠正我开始!

现在,如果Android带有自己的编译器(它可能会),并以与不同(符合Dalvik标准)的方式编译Java源代码,那么我可以理解为什么一些代码(未使用Android SDK编译)无法在Android设备上运行:javac

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

但是,看起来您用于编译Android应用程序!?!?所以看起来我们有这个:javac

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

如果用于将所有源代码编译为字节码,那么为什么Dalvik不能运行某些类型的Java代码?javac

我昨天问了一个非常相似的问题,尽管在技术上得到了答案(在重新阅读了我的问题之后,我发现我只是不够具体),但没有人能够解释Dalvik固有的是什么,使得不可能从Google Guice或Apache Camel等项目运行Java代码。我被告知,为了让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代码。我试图了解哪些类型的Java代码在“馈送到”Dalvik JVM时不会运行。

编辑:在“但骆驼3.0将在Android上运行!我知道 - 不是我的问题!


答案 1

我试图了解哪些类型的Java代码在“馈送到”Dalvik JVM时不会运行。

Dalvik JVM在以下几个方面与其他JVM不同:

  • 它使用特殊的DEX格式来存储标准Java虚拟机使用的应用程序二进制文件与.JAR和Pack200格式。谷歌声称DEX导致比JAR更小的二进制文件。我认为他们可以使用Pack200取得同样的成功,但他们决定在这方面走自己的路。

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

  • Dalvik JVM使用基于寄存器的架构与其他JVM的基于堆栈的架构,旨在加快执行速度并减少二进制大小

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

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

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

  • 基于 Parcel 和 Parcelable 类的特殊对象序列化机制。从功能上讲,它与标准的Java Serializable具有相同的目的,但导致更少的数据占用空间,并且可能对类版本的差异更加宽松。

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

  • 在Android 2.2之前,Dalvik JVM不支持JIT编译,这对Android应用程序的性能产生了不利影响。在 2.2 中添加它可显著提高常用应用程序的执行速度


答案 2

如果到目前为止我所说的任何话都是不正确的,请从纠正我开始!

嗯, 嗯...

  • 与移动环境的 Java VM 相比,Dalvik VM 具有技术优势,最明显的是积极使用写入时复制内存共享,因此整个 VM 和标准类库在所有 Android SDK 应用进程之间共享,从而减少了每个进程的净内存占用量。请参阅user370305的答案(在我总结本文时发布)以获取更多信息。

  • 作为 Android 应用程序构建过程的一部分,从 的字节码被交叉编译为 Dalvik 字节码。Java VM 不能执行 Dalvik 字节码,就像它不能执行 的输出一样;同样,Dalvik VM无法执行Java字节码。javac/dev/random

这是我大约两年前的一篇博客文章,其中谈到了其他要点。

如果javac用于将所有源代码编译为字节码,那么为什么Dalvik不能运行某些类型的Java代码呢?

因为字节码输出是交叉编译的。交叉编译器()处理非常特定的输出风格,这意味着虽然它适用于经典(你从 java.sun.com 获得的)和Java 1.5和1.6的OpenJDK,但它不适用于替代编译器(例如GCJ),并且至少不能与Java 7中的任何新字节码一起使用。javacdxjavacjavac

没有人能够解释Dalvik固有的是什么,使得不可能从Google Guice或Apache Camel等项目运行Java代码。

就个人而言,我从未使用过Google Guice,尽管Roboguice可以在Android上运行。在你的问题之前,我从未听说过Apache Camel,并且相当困惑地发现它不是Perl的Java端口。:-)

任何执行运行时 JVM 字节码生成的工具都无法在 Android 上运行,这仅仅是因为交叉编译器仅在编译时可用,而在运行时不可用。另外,我不熟悉运行时JVM字节码生成工具使用的技术,以及它们如何让JVM执行该字节码,因此我不知道Android中是否存在等效的钩子来让Dalvik运行任意Dalvik字节码块。

但是,由于您拒绝确切说明您遇到的问题“来自Google Guice或Apache Camel等项目的Java代码”,并且由于我对这些项目不熟悉,因此很难进一步评论。


推荐