Android:javac vs Dalvik

IAm*_*aja 25 java android javac dalvik

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

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

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

现在,如果Android带有自己的编译器(它可能),并以不同的(Dalvik兼容)方式编译Java源代码javac,那么我可以理解一些代码(不是用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
Run Code Online (Sandbox Code Playgroud)

但是,它看起来像你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 (???)
Run Code Online (Sandbox Code Playgroud)

如果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 !!! (???)
Run Code Online (Sandbox Code Playgroud)

显然,Dalvik JVM内部正在发生一些事情,阻止它运行某些类型的Java代码. 我试图了解当"馈入"Dalvik JVM时,哪些类型的Java代码不会运行.

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

use*_*305 28

I'm trying to understand what types of Java code will not run when "fed" into the Dalvik JVM.
Run Code Online (Sandbox Code Playgroud)

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中添加它可以显着提高常用应用程序的执行速度

  • 另外... dx用于将一些(但不是全部)Java .class文件转换为.dex格式.多个类包含在单个.dex文件中.多个类文件中使用的重复字符串和其他常量仅在.dex输出中包含一次以节省空间.Java字节码也被转换为Dalvik VM使用的备用指令集.未压缩的.dex文件的大小通常比从相同.class文件派生的压缩.jar(Java Archive)小几个百分点. (2认同)
  • Re:使用pack200 - 这只会节省存储空间,它仍然需要以未压缩的形式加载到内存中.Dex文件小于一组未压缩的.class文件,因此加载时它们占用的内存较少. (2认同)

Com*_*are 24

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

嗯,好吧......

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

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

以下是我大约两年前发表的一篇博文,其中包含了更多内容.

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

因为javac字节码输出是交叉编译的.cross-compiler(dx)处理一种非常特殊的javac输出风格,这意味着虽然它适用于经典javac(你可以从java.sun.com获得)和OpenJDK for Java 1.5和1.6,但它不能与替代编译器一起使用(例如,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代码"您遇到了什么问题,并且由于我对这些项目并不熟悉,因此很难进一步评论.

  • @CommonsWare - DexMaker是运行时字节码生成的工具.虽然它不是替代品,但是要使用在Android上生成动态字节码的任何东西,您首先必须移植该工具才能使用DexMaker. (8认同)

ali*_*dro 11

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

在这里,我举一个例子来说明一些不同之处.

Hello.java

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

用于javac编译Hello.java为java字节码Hello.class

$ javac Hello.java
Run Code Online (Sandbox Code Playgroud)

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

$ $ANDROID_SDK_ROOT/build-tools/21.1.2/dx --dex --output=Hello.dex Hello.class
Run Code Online (Sandbox Code Playgroud)

在此之后,使用adb投入Hello.classHello.dex对Android设备或模拟器.

$ adb push Hello.class /data/local/tmp/
$ adb push Hello.dex /data/local/tmp/
Run Code Online (Sandbox Code Playgroud)

用于adb shell进入Android设备的shell环境.然后使用命令/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!!!!
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,当我们使用java字节码时Hello.class,dalvikvm抱怨错误,如果我们将类更改为dalvik可执行文件Hello.dex,它将正常运行.