4

我的教授对一个小程序做了一个非正式的基准测试,Java 时间是:第一次运行 1.7 秒,之后运行 0.8 秒。

  • 这完全是由于将运行时环境加载到操作环境中吗?

    或者

  • 它是否受到 Java 优化代码和存储这些优化结果的影响(对不起,我不知道技术术语)?

4

6 回答 6

5

好的,我找到了我读到的地方。这全部来自“学习 Java”(O'Reilly 2005):

传统 JIT 编译的问题在于优化代码需要时间。因此,JIT 编译器可以产生不错的结果,但在应用程序启动时可能会出现明显的延迟。对于长时间运行的服务器端应用程序来说,这通常不是问题,但对于在功能有限的小型设备上运行的客户端软件和应用程序来说却是一个严重的问题。为了解决这个问题,Sun 的称为 HotSpot 的编译器技术使用了一种称为自适应编译的技巧。如果您查看程序实际花费时间在做什么,就会发现它们几乎将所有时间都花在一次又一次地执行相对较小的部分代码上。重复执行的代码块可能只是整个程序的一小部分,但它的行为决定了程序的整体性能。

为了利用这一事实,HotSpot 一开始是一个普通的 Java 字节码解释器,但有一点不同:它在代码执行时测量(分析)代码,以查看哪些部分正在重复执行。一旦知道代码的哪些部分对性能至关重要,HotSpot 就会将这些部分编译为最佳的本机机器代码。由于它只将程序的一小部分编译成机器代码,因此它可以花费必要的时间来优化这些部分。程序的其余部分可能根本不需要编译——只需解释——节省内存和时间。事实上,Sun 的默认 Java VM 可以运行在两种模式中的一种:客户端和服务器,这告诉它是强调快速启动时间和内存节省还是平坦性能。

此时要问的一个自然问题是,为什么每次应用程序关闭时都丢弃所有这些好的分析信息?嗯,随着 Java 5.0 的发布,Sun 通过使用以优化形式永久存储的共享只读类部分地提出了这个主题。这显着减少了在给定机器上运行许多 Java 应用程序的启动时间和开销。这样做的技术很复杂,但想法很简单:优化程序中需要快速运行的部分,其余部分不用担心。

我有点想知道自 Java 5.0 以来 Sun 已经用它走了多远。

于 2008-09-16T00:20:27.880 回答
4

我不知道有任何广泛使用的虚拟机可以在程序调用之间保存统计使用数据——但这对于未来的研究来说无疑是一个有趣的可能性。

您所看到的几乎可以肯定是由于磁盘缓存。

于 2008-09-16T00:07:55.713 回答
2

我同意这可能是磁盘缓存的结果。

仅供参考,IBM Java 6 VM 确实包含提前编译器 (AOT)。代码不像 JIT 生成的那样优化,但它存储在 VM 之间,我相信某种持久共享内存。它的主要好处是提高启动性能。默认情况下,IBM VM 在调用 1000 次后 JIT 方法。如果它知道一个方法将在 VM 启动期间被调用 1000 次(想想一个常用的方法java.lang.String.equals(...),如运行。

于 2008-09-16T01:38:40.597 回答
1

我同意海报看到的性能差异很可能是由于磁盘延迟将 JRE 带入内存造成的。即时编译器 (JIT) 不会对小应用程序的性能产生影响。

Java 1.6u10 ( http://download.java.net/jdk6/ ) 在后台进程(即使 Java 没有运行)中接触运行时 JAR,以将数据保存在磁盘缓存中。这显着减少了启动时间(这对桌面应用程序来说是一个巨大的好处,但对服务器端应用程序可能具有边际价值)。

在大型、长时间运行的应用程序中,JIT 会随着时间的推移产生很大的不同 - 但与整体生命周期相比,JIT 积累足够的统计数据以启动和优化所需的时间(5-10 秒)非常非常短应用程序(大多数运行数月和数月)。虽然存储和恢复 JIT 结果是一项有趣的学术练习,但实际改进并不是很大(这就是为什么 JIT 团队更专注于诸如 GC 策略以最小化内存缓存未命中等的原因......)。

运行时类的预编译确实对桌面应用程序有很大帮助(就像前面提到的 6u10 磁盘缓存预加载一样)。

于 2008-09-16T04:35:44.773 回答
1

您应该描述您的基准测试是如何完成的。尤其是在您开始测量时间的时候。

如果您包括 JVM 启动时间(这对基准测试用户体验很有用,但对优化 Java 代码没那么有用),那么它可能是文件系统缓存效应,或者它可能是由称为“Java 类数据共享”的特性引起的:

对于太阳:

http://java.sun.com/j2se/1.5.0/docs/guide/vm/class-data-sharing.html

这是一个选项,JVM 将准备好的运行时类图像保存到文件中,以便在下次启动时更快地加载(和共享)这些图像。您可以通过 Sun JVM 使用 -Xshare:on 或 -Xshare:off 来控制它。默认值为 -Xshare:auto ,如果存在,它将加载共享类图像,如果不存在,如果目录可写,它将在第一次启动时写入它。

使用 IBM Java 5,BTW 更加强大:

http://www.ibm.com/developerworks/java/library/j-ibmjava4/

我不知道有任何主流 JVM 可以保存 JIT 统计信息。

于 2008-09-16T18:06:16.883 回答
0

Java JVM(实际上可能会从不同的 JVM 实现中改变)在刚开始时会解释字节码。一旦它检测到代码将运行足够多次 JIT 将其转换为本地机器语言,它就会运行得更快。

于 2008-09-16T00:09:22.073 回答