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

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

    或者

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

有帮助吗?

解决方案

我同意发帖者所看到的性能差异很可能是由将 JRE 引入内存的磁盘延迟引起的。即时编译器 (JIT) 不会对小型应用程序的性能产生影响。

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

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

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

其他提示

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

传统 JIT 编译的问题是优化代码需要时间。因此,JIT 编译器可以产生不错的结果,但在应用程序启动时可能会出现明显的延迟。对于长时间运行的服务器端应用程序来说,这通常不是问题,但对于在功能有限的较小设备上运行的客户端软件和应用程序来说,这是一个严重的问题。为了解决这个问题,Sun 的编译器技术(称为 HotSpot)使用了一种称为自适应编译的技巧。如果你看看程序实际花时间做什么,就会发现它们几乎所有时间都花在一次又一次执行相对较小的代码部分。重复执行的代码块可能只占整个程序的一小部分,但其行为决定了程序的整体性能。自适应编译还允许 Java 运行时利用静态编译语言无法完成的新型优化,因此有人声称 Java 代码在某些情况下可以比 C/C++ 运行得更快。

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

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

我有点想知道 Sun 自 Java 5.0 以来已经发展到什么程度了。

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

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

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

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

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

如果包含 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,这甚至更强大:

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

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

Java JVM(实际上可能会因 JVM 的不同实现而发生变化)在第一次启动时会解释字节码。一旦它检测到代码将运行足够的次数,就会将其 JIT 为本机机器语言,以便运行得更快。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top