28

我的理解是,Google 不喜欢 Oracle 在 Java ME 中使用 JRE 的许可政策,所以它只是使用自己的 JVM 规范重写了它,该规范模仿了 JRE,但行为略有不同,尤其是在提高效率和更安全。

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

如果到目前为止我所说的任何内容都不正确,请先纠正我!

现在,如果 Android 带有自己的编译器(它可能),并以不同的(Dalvik 兼容)方式编译 Java 源代码javac,那么我可以理解某些代码(未使用 Android SDK 编译)如何无法在安卓设备:

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 代码的原因来自 Google Guice 或 Apache Camel 等项目。有人告诉我,为了让 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 时不会运行。

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

4

3 回答 3

30
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 应用程序

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

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

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

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

于 2012-07-07T11:27:29.153 回答
25

如果到目前为止我所说的任何内容都不正确,请先纠正我!

嗯,嗯……

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

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

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

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

因为javac字节码输出是交叉编译的。交叉dx编译javacjavac( (例如,GCJ),并且至少不能与 Java 7 中的任何新字节码一起使用。

没有人能够解释 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 代码”,并且由于我对这些项目并不十分熟悉,因此很难进一步评论。

于 2012-07-07T11:28:14.637 回答
13

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

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

你好.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

然后使用dxandroid sdk 中的工具将 java 字节码转换Hello.classHello.dex

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

之后,用于adb放置Android 设备或模拟器。Hello.classHello.dex

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

用于adb shell进入安卓设备的shell环境。然后使用命令/system/bin/dalvikvm执行我们刚刚创建的简单javaHello.class程序Hello.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,它会正常运行。

于 2015-01-13T04:33:07.040 回答