Java本机编译(转载)
2007-07-29 20:19
281 查看
衡量 Java 本机编译从 Java 源程序生成本机代码的优缺点原文: http://www.ibm.com/developerworks/cn/java/j-native/ ![]() |
![]() | 级别: 初级 Martyn Honeyford, 软件工程师, IBM 英国实验室 2002 年 1 月 18 日 一开始引入 Java 本机编译时,它似乎一定能胜过 JVM,抛弃 Java 平台极力争取的平台无关性。但是即使本机编译越来越流行,并且市场上的本机编译器越来越多,它要真正取代 Java 的可移植性还有一段路要走。不幸的是,就连该技术成熟到足以解决目前让许多人头疼的 Java 性能问题也还尚需时日。请在 论坛中将您对本文的想法与作者和其它读者一起共享。 尽管 Java 语言有许多优点,但是仍然存在几个问题限制了在关键项目中的使用。它们包括执行速度、内存占用、磁盘占用以及 JVM 可用性。虽然 JIT 编译器极大改进了平台的执行速度,J2ME 大幅降低内存占用,但是在许多领域中,Java 应用程序完全无法和它们本机的竞争对手(通常是 C/C++)竞争。为了解决这些问题,许多开发人员已经转向使用 Java 本机编译器,它们允许用 Java 语言编写应用程序,然后将它们编译成本机可执行程序。这种解决方案将以平台无关性为代价,但是它可以导致更快的执行速度和更小的内存占用,这些对于当今许多应用程序都很关键。 为使您能快速掌握 Java 本机编译技术,我们将首先讨论代码编译基础,包括为什么许多开发人员正在使用 Java 本机编译器编译他们的应用程序的简要概述。接下来,我们将使用自由软件编译器和两个不同的应用程序(一个很简单,另一个复杂一些)来测试 Java 本机编译的结果。这些示例和所产生的度量结果将作为研究如何比较最新的 Java 本机编译器和 JVM 的第一手资料。 代码编译基础 要理解本文讨论的内容,您应该熟悉三种最常用的代码编译方法: 使用 Java 编译器(例如,javac)编译 Java 代码 编译本机代码,例如针对特定硬件/操作系统(OS)平台的 C/C++ 使用针对特定硬件/OS 平台的 Java 本机编译器来编译 Java 代码 使用 Java 编译器编译 Java 代码是最简单的。我们只要用 Java 语言编写源代码,使用 Java 编译器将源代码编译成 Java 字节码,然后就可以在任何安装了 JVM 的硬件/OS 平台上执行结果了。其缺点是 Java 依赖于 JVM 来实现其特点“一次编写,随处运行”可移植性;不仅要在运行 Java 应用程序的任何平台上安装有可用的 JVM,而且必须还有大量系统资源(内存和磁盘空间)用以支持 JVM。因此,许多开发人员仍然依靠不太灵活但却更具针对性的语言,例如,C/C++。 编译 C/C++ 源程序与编译 Java 源程序相似。只要编写了代码,我们通过一个针对特定硬件/OS 平台的编译器和链接器来运行它。只有在目标平台上才可以执行生成的应用程序,但是不需要安装 JVM(虽然它可能需要一些支持共享库,这取决于所使用的语言)。几乎使用这种方法开发的最简单的应用程序都必须针对每个要运行它们的硬件/OS 平台单独定制。 第三种方法尝试结合以上两种解决方案的优点,允许开发人员使用 Java 语言编写应用程序,然后将它们编译成本机可执行程序。编写了 Java 代码之后,就可以通过 Java 编译器生成 Java 字节码,然后将 Java 字节码编译成本机代码来运行它,或者在 Java 本机编译器中直接运行 Java 代码。需要的步骤数取决于所使用的编译器的需求。 这种方法的优点是可以在 未安装 JVM的目标平台上执行结果代码。这样做的目的是使 Java 应用程序以更快的速度执行,大幅降低运行所需的磁盘空间和内存(虽然有必要为 Java 本机编译器提供支持资源库)。 编译器的目标平台、它们提供的 Java 支持级别以及它们使用的系统资源的数量都是不相同的。在本文的 参考资料一节中可以找到一些当前可用的本机编译器的清单。
对市场上每种本机编译器的功能部件和性能进行比较已经大大超越了本文的范围。我使用一种编译器 ― GNU 编译器 Java 编程语言版(GNU Compiler for the Java Programming Language, GCJ)作为示例来详细说明本机编译的过程与结果。GCJ 是一种为 GNU 编译器集(GNU Compiler Collection,GCC)开发的编译器,GNU 编译器集是 GNU 项目的一部分。与其它出自 GNU 项目的所有软件一样,GCJ 是双重意义上的自由软件,因此可以很容易地获取(请参阅 参考资料)。如果您正在认真考虑您产品的本机编译途径,当然应该尽可能多地评估编译器,或许可以使用本文中建立的标准。 我的测试系统硬件是一台装有 450 MHz Pentium II 处理器和 320 MB 内存的 PC 机。操作系统是最近安装的 Mandrake 8.1 Linux 分发版。这个分发版带有 GCJ 的 3.0.1 版本,它包含在 GCC 3.0.1 中并且作为 8.1 Mandrake 分发版一部分提供。 我已经运行了两个独立的应用程序,一个很简单,另一个复杂一些。为了比较系统和 Java 平台的性能,我将应用程序编译成 Java 字节码。我使用 Sun JDK 版本 1.3.1.02 Linux 版来编译 Java 代码,然后在下列 JVM 上测试结果类: Kaffe 1.0.6 Sun JVM 1.3.1_02 IBM JRE 1.3.1 为实现本文的目的,我测量了执行速度、执行内存开销和磁盘空间。
第一个测试应用程序很简单,由单一类 prime.java 组成。这个应用程序实现一个非常基本的搜索质数的算法。 清单 1 显示了 prime.java 的源代码。 清单 1. prime.java 的源代码 我使用下列命令将 prime.java 编译成本机可执行程序: -O3表示“优化速度”;参数 --main告诉 GCJ 哪一个类包含运行应用程序时将使用的 main 方法;参数 -o Prime命名生成的可执行程序。有关一套完整的命令行参数,请参阅 GCJ 文档。 为了编译 Java 字节码测试,我使用了下列命令: 本机: ./prime Kaffe: /usr/bin/java prime Sun JDK: /usr/java/jdk1.3.1_02/bin/java prime IBM JRE: /opt/IBMJava2-13/jre/bin/java prime prime.java 的测试结果 如前所述,我测试了执行速度、内存使用和磁盘空间使用情况。下表详细说明了第一个测试的结果。 表 1. Prime.java:执行速度
简单来说,如果一个进程分配了大量内存,这会显示在 VM 大小中,但是直到真正被使用(例如,读或写)时才会显示在 VM RSS 中。实际上,VM RSS 是更重要的测量指标,因为它更准确地反映了系统的性能。 表 3. Prime.java:磁盘空间使用
对于第二个测试,我使用了一个更复杂的 Java 应用程序 SciMark 2 Java 基准测试程序。可以免费获得本文使用的命令行版本(请参阅 参考资料)。SciMark 2 是一个很复杂的应用程序。它实现了许多用来准确地评测 JVM 的效率的基准测试程序。 我使用下列命令将 SciMark 2 编译成本机可执行程序: 我使用下列命令以正常模式调用代码: 本机: ./scimark Kaffe: /usr/bin/java jnt.scimark2.commandline Sun JDK: /usr/java/jdk1.3.1_02/bin/java jnt.scimark2.commandline IBM JRE: /opt/IBMJava2-13/jre/bin/java jnt.scimark2.commandline 对于更大的问题集,我使用下列命令: 本机: ./scimark -large Kaffe: /usr/bin/java jnt.scimark2.commandline -large Sun JDK: /usr/java/jdk1.3.1_02/bin/java jnt.scimark2.commandline -large IBM JRE: /opt/IBMJava2-13/jre/bin/java jnt.scimark2.commandline -large SciMark 2 的测试结果 以下各表显示了编译 SciMark 2 的结果。请注意结果中正常模式与大模式的区别。 表 4. SciMark 2,正常模式:执行速度
从上面的测试结果应该明显看出,Java 本机编译究竟是成功还是失败还难有定论。某些基准测试程序显示在本机编译的可执行程序比使用某些 JVM 版本快;另外一些则相反。同样,不同 JVM 之间,某些操作的速度也大相径庭。执行的“工作集”内存测试显示执行时在内存使用方面并没有很大差别。要进一步探索该领域,可以采用不同的垃圾信息收集方案来进行本机和 JVM 测试。 本机版本只是在磁盘空间使用方面明显优于 JVM 版本,而且只有当考虑到 JVM 的大小时,这才能成立。虽然类本身很小,但是所测试的 JVM 却很大(IBM 和 Sun JVM 的 jre 子目录中的递归目录清单显示仅是 JRE 就占用了 50 MB 磁盘空间)。但是,请不要忘记还可以使用许多更小的 JVM,虽然 JVM 和单个应用程序的组合比本机可执行程序与 GCJ 运行时库 libgcj.so(少于 3 MB)的组合大得多,但是本机版本的可执行程序的大小却大很多。因此,在需要大量应用程序的情况下,JVM 版本可能是最终的赢家。 除了这些有点模糊的结果之外,使用 Java 本机编译还可能产生许多潜在问题。它们是: 失去了平台无关性:实际上,这并不是什么大不了的问题。因为源程序是用 Java 语言编写的,所以您仍然可以选择生成可以在任何地方运行的 Java 字节码版本,然后按需要在特定平台上使用本机编译器。 类支持/编译器成熟度:某些编译器仍然相对不太成熟,并且可能无法支持您应用程序所需的所有 Java 类。例如,虽然 GCJ 支持大部分上至 1.1 版本规范的 Java 语言构造,但是,它 不支持通常与 JVM 一起提供的所有 Java 类库。最重要的是,它几乎不支持 AWT,这使 GCJ 无法适用于 GUI 应用程序。不同的编译器支持不同级别的类库;Excelsior JET 声称是完全支持 AWT 和 Swing 的编译器。 支持/复杂程度:因为这个领域相对较新,所以开发人员常常无法很好地了解它。诊断工具可能在基础上有点薄弱,所以要诊断本机编译的 Java 应用程序中发生的问题可能更困难(尤其当 Java 字节码版本中没有发生该错误时)。
当开发应用程序时,通常确定 Java 本机编译是否适合您的特定环境的唯一实际方法是完成一个问题解决周期。 确定希望使用本机编译来解决的确切问题。 研究可用的本机编译器,然后提出一些可能解决问题的本机编译器。 尝试您选择的所有编译器来编译您的应用程序,然后观察结果。 尽管 Java 本机编译技术还比较稚嫩,并且缺少明确的结果,但它却是 Java 语言中一个激动人心的新领域。利用现有选项的最佳方法是,或许可以使用本文中建立的某些方法和标准亲自研究和测试 Java 本机编译。 虽然本机编译不会取代 JVM(许多人认为它会取代 JVM),但是已经证明,对于某些应用程序和环境,它是正确的解决方案。本机编译将 Java 语言的使用范围扩展到一些新领域,短短几年前在这些领域中还无法应用 Java 语言。整体而言,这仅对于 Java 语言和 Java 社区是件好事。
您可以参阅本文在 developerWorks 全球站点上的 英文原文. 请参加关于本文的 论坛。 请访问 GNU Compiler for the Java Programming Language主页以了解有关 GCJ 和 GNU 编译器集合的更多信息。 SciMark 2.0 是用来评测科学和工程应用程序中数学计算代码性能的基准测试程序的组合。请访问 SciMark 2.0 主页以了解更多关于这种复杂应用程序的信息。 从“ 弥补和 COM 的缝隙”(developerWorks,2001 年 10 月)中了解如何重用不是用 Java 语言编写的代码。 当无法在应用程序中采用一个纯 Java 语言解决方案时,仍然可以有效地调试 Java/C 混合体。Matthew White 在“ 调试集成的 Java 和 C/C++ 代码”(developerWorks,2001 年 11 月)中解释了如何完成该操作。 在 developerWorks Java 技术专区中可以找到更多 Java 参考资料。 可选择的 Java 本机编译器 GCJ BulletTrain Excelsior JET JOVE TowerJ Visual Cafe VisualAge for Java FastJ
|
相关文章推荐
- 使用Ant编译Java工程(转载)
- (转载)JAVA动态编译--字节代码的操纵
- 防止java反编译的一些常用方法(转载)
- JAVA->编译环境软件EDITPLUS(转载)
- java编译环境设置(转载)
- (转载)JVM学习笔记(二)------Java代码编译和执行的整个过程
- 转载:回编译APK出错:java.nio.char set.MalformedInputException: Input length = 1
- 使用Ant编译Java工程(转载)
- Java 面试题问与答:编译时与运行时(转载)看了一遍还不是很懂 先收着
- Java动态编译一个简单的例子(我转载的,但是经过修定,可以在Eclipse下运行)
- Java语言的编译,链接,转载
- java 导入的项目不自动编译问题
- 常见Java面试题 [转载待续]
- 数据结构二叉树的递归与非递归遍历之java,javascript,php实现可编译(1)java
- [转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
- eclipse JAVA反编译
- Android编译出现Multiple substitutions specified in non-positional format (转载)
- (转载)JAVA小知识
- Java中class文件编译成exe文件的几种方法
- 转载:交叉编译inetutils并配置telnet服务