java Android:javac 与 Dalvik

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11374477/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 04:49:08  来源:igfitidea点击:

Android: javac vs Dalvik

javaandroidjavacdalvik

提问by IAmYourFaja

My understanding is that Google didn't like Oracle's licensing policy for using the JRE in Java ME so it just rewrote it using its own JVM specification that mimicsthe JRE but behaves a little bit differently, especially when it comes to making things more efficient and more secure.

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

So, if my understanding is correct, it means that when javacis ran on some Java source code and compiled into "binary" byetcode, a compliant JVM will interpret that bytecode different than Dalvik will (in some cases). This is the inherent difference between Dalvik and other (compliant) JVMs.

因此,如果我的理解是正确的,这意味着当javac在某些 Java 源代码上运行并编译为“二进制”字节码时,兼容的 JVM 将解释该字节码,而不是 Dalvik(在某些情况下)。这是 Dalvik 和其他(兼容)JVM 之间的内在差异。

If anything I have said so far is incorrect, please begin by correcting me!

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

Now, if Android came with its own compiler (which it might), and compiled Java source in a different (Dalvik-compliant) manner than javac, then I could understand how some code (not compiled with the Android SDK) would not run on an Android device:

现在,如果 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

However, it looks like you use javacto compile Android apps!?!? So it looks like we have this:

但是,看起来你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 (???)

If javacis used to compile all sources into bytecode, then why is it that Dalvik can't run some types of Java code?

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

I asked a very similar question yesterday and although it was technically answered (after re-reading my question I see I was simply not specific enough) no one was able to explain what it is that's inherent to Dalvik that makes it impossible to run Java code from projects like Google Guice or Apache Camel. I was told that in order to get Camel to run on Dalvik, that I would have to get Camel's source and then it would have to be "built with the Android SDK", but I couldn't get clarity on what that meant or implied.

我昨天问了一个非常相似的问题,虽然它在技术上得到了回答(在重新阅读我的问题后,我发现我的问题不够具体)没有人能够解释 Dalvik 固有的使 Java 代码无法运行的原因来自 Google Guice 或 Apache Camel 等项目。有人告诉我,为了让 Camel 在 Dalvik 上运行,我必须获得 Camel 的源代码,然后它必须“使用 Android SDK 构建”,但我无法弄清楚这意味着什么或暗示了什么.

With Camel, for instance, you have this (simplified):

例如,对于 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 !!! (???)

Clearly, something is happening inside the Dalvik JVM that prevents it from running certain types of Java code. I'm trying to understand what types of Java code will not run when "fed" into the Dalvik JVM.

很明显,Dalvik JVM 内部发生了一些事情,阻止它运行某些类型的 Java 代码。 我试图了解当“输入”到 Dalvik JVM 时哪些类型的 Java 代码不会运行。

Edit:In before "but Camel 3.0 will run on Android!" I know - not my question!

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

回答by user370305

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

Dalvik JVM differs from other JVMs in following aspects:

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

  • It uses special DEX format for storing applications binaries vs. JAR and Pack200 formats used by standard Java virtual machines. Google claims that DEX results in smaller binaries than JAR. I think they could use Pack200 with the same success, but they decided to go their own way in this aspect

  • Dalvik JVM was optimized for running multiple JVM processes simultaneously

  • Dalvik JVM uses register-based architecture vs. stack based architecture of other JVMs with intent to speed up execution and to reduce binary sizes

  • It uses its own instructions set (not a standard JVM bytecode)

  • One can run (if needed) several independent Android applications within a single JVM process

  • Application execution can span across several Dalvik JVM processes “naturally”. To support this it adds:

    • Special object serialization mechanism based on Parcel and Parcelable classes. Functionally it serves the same purpose as standard Java Serializable, but results in smaller data footprint and is potentially more lenient towards differences in versions of classes

    • Special Android way to execute inter process calls (IPC) based on Android Interface Definition Language (AIDL)

  • Until Android 2.2 Dalvik JVM did not support JIT compilation which adversely impacted Android application performance. Adding it in 2.2 improves markedly execution speed for often used applications

  • 与标准 Java 虚拟机使用的 JAR 和 Pack200 格式相比,它使用特殊的 DEX 格式来存储应用程序二进制文件。Google 声称 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 中添加它显着提高了常用应用程序的执行速度

回答by CommonsWare

If anything I have said so far is incorrect, please begin by correcting me!

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

Ummm, well...

嗯,嗯...

  • The Dalvik VM has technical advantages over the Java VM for mobile environments, most notably aggressive use of copy-on-write memory sharing, so the entire VM and standard class library is shared among all Android SDK app processes, reducing the net per-process memory footprint. See user370305's answer (posted while I was wrapping this up) for more.

  • The bytecode from javacis cross-compiled into Dalvik bytecode as part of the Android application build process. The Java VM cannot execute Dalvik bytecode any more than it can execute the output of /dev/random; similarly, the Dalvik VM cannot execute Java bytecode.

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

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

Here is a blog post of minefrom around two years ago that goes into additional points.

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

If javac is used to compile all sources into bytecode, then why is it that Dalvik can't run some types of Java code?

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

Because the javacbytecode output is cross-compiled. The cross-compiler (dx) handles a very specific flavor of javacoutput, meaning that while it works with the classic javac(what you would have gotten from java.sun.com) and OpenJDK for Java 1.5 and 1.6, it will not work with alternative compilers (e.g., GCJ) and, at minimum, will not work with any new bytecodes from Java 7.

因为javac字节码输出是交叉编译的。交叉编译器 ( dx) 处理一种非常特殊的javac输出,这意味着虽然它可以与经典javac(您可以从 java.sun.com 获得的)和 Java 1.5 和 1.6 的 OpenJDK 一起使用,但它不能与其他编译器一起使用(例如,GCJ)并且至少不会与来自 Java 7 的任何新字节码一起使用。

no one was able to explain what it is that's inherent to Dalvik that makes it impossible to run Java code from projects like Google Guice or Apache Camel

没有人能够解释 Dalvik 的内在原因是什么导致无法运行来自 Google Guice 或 Apache Camel 等项目的 Java 代码

Personally, I have never used Google Guice, though Roboguiceworks on Android. I had never heard of Apache Camel prior to your question and am rather confused to find that it is not a Java port of Perl. :-)

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

Any tools that do runtime JVM bytecode generation will not work on Android, simply because the cross-compiler is only available at compile-time, not run-time. Also, I am unfamiliar with the techniques used by runtime JVM bytecode-generating tools and how they get the JVM to execute that bytecode, and therefore I do not know if equivalent hooks exist in Android to have Dalvik run arbitrary chunks of Dalvik bytecode.

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

However, since you declined to specify exactly what "Java code from projects like Google Guice or Apache Camel" you are having problems with, and since I am not intimately familiar with those projects, it is difficult to comment further.

但是,由于您拒绝具体说明您遇到问题的“来自 Google Guice 或 Apache Camel 等项目的 Java 代码”究竟是什么,而且由于我对这些项目并不十分熟悉,因此很难进一步发表评论。

回答by alijandro

This picture from Android official document illustrate the build process of Android APK, it will help to understand the difference between java bytecode and dalvik executable. enter image description here

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

Here I give an example to demonstrate some of the differences.

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

Hello.java

你好.java

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

use javacto compile Hello.javato java bytecode Hello.class

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

$ javac Hello.java

Then use dxtool from android sdk convert java bytecode Hello.classto Hello.dex

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

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

After that, use adbto put Hello.classand Hello.dexto Android device or emulator.

之后,使用adbto put Hello.classand Hello.dexto Android 设备或模拟器。

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

use adb shellto enter the shell environment of Android device. Then use the command /system/bin/dalvikvmto execute the simple java program we just created Hello.classand Hello.dex

用于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!!!!

In the example above, when we use the java bytecode Hello.class, dalvikvmcomplaint error, if we changed the class to dalvik executable Hello.dex, it would run properly.

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