【问题标题】:Java application CPU/load much higher when built against JDK8针对 JDK8 构建的 Java 应用程序 CPU/负载要高得多
【发布时间】:2015-04-23 13:18:21
【问题描述】:

我有一个在 Windows 的 Eclipse Luna 中开发的 Java 应用程序,它在 Amazon EC2(c3.large,Amazon Linux)中运行。此应用程序进程以非常一致的传入速率工作。当我针对 JDK 8u31 构建应用程序时,EC2 CPU 负载远高于针对 JDK 7u75 构建的相同应用程序。

该应用程序最初使用 EC2 上的默认 JRE 运行,我添加了 OpenJDK 1.8.0.31 以利用 Java 8 Process waitFor(long timeout, TimeUnit unit)。此应用程序的主要工作涉及使用 Runtime.exec 调用应用程序。

$ sudo alternatives --config java

There are 2 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
*  1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
 + 2           /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.31-2.b13.5.amzn1.x86_64/jre/bin/java

基于 1.7 构建应用程序时的示例负载平均:

top - 00:20:28 up 4 days, 10:41,  4 users,  load average: 0.37, 0.26, 0.52

基于 1.8 构建应用程序时的示例负载平均:

top - 23:45:52 up 4 days, 10:06,  4 users,  load average: 2.28, 2.60, 2.01

似乎它可能与 Open JDK 1.8.0.31 有关,但我不知道如何调试。没有代码更改,我只是在 Eclipse Luna 中更改合规级别并在 1.7 和 1.8 之间构建。知道为什么负载会有如此大的不同吗?

更新:

当我在 EC2 上使用 Oracle JDK 时,我看到类似的高 CPU 负载。

$ sudo alternatives --config java

There are 3 programs which provide 'java'.

  Selection    Command
-----------------------------------------------
   1           /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
   2           /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.31-2.b13.5.amzn1.x86_64/jre/bin/java
*+ 3           /usr/java/jdk1.8.0_31/bin/java

平均负载:

top - 01:45:27 up 4 days, 12:06,  4 users,  load average: 2.28, 1.50, 1.04

【问题讨论】:

  • 你能在自己的机器上重现这个吗?
  • 我在多个 EC2 实例(都是 OpenJDK)上见过它。我无法在本地机器上生成工作负载,但我会研究模拟工作的方法。
  • 区分编译器与 jre 的效果:如果您在合规性 1.7 上编译并在 1.8 jre 上运行会发生什么?
  • 这两个版本有区别吗?也就是说,您是否为两者编译完全相同的源?您提到您添加了OpenJDK 1.8.0.31 to take advantage of the Java 8 Process waitFor(long timeout, TimeUnit unit),因此如果您已经实施了该更改,您可能会遇到基于代码的问题。
  • 所以这似乎排除了由于使用不同的 API 而造成的差异。但是我们仍然不知道,为 1.7 构建并在 1.8 上运行的 jar 是否显示相同的效果(请参阅我之前的评论)。该实验将清楚地表明问题是需要在编译器级别还是在 JVM 级别进行分析。

标签: java eclipse amazon-ec2 java-8


【解决方案1】:

文档说:“此方法的默认实现会轮询 exitValue 以检查进程是否已终止。强烈建议此类的具体实现以更有效的实现覆盖此方法。”

我强烈怀疑这就是原因。

http://docs.oracle.com/javase/8/docs/api/java/lang/Process.html#waitFor--

【讨论】:

  • 我认为在使用 process.waitFor(30, TimeUnit.SECONDS) 的情况下是可能的。没有说明没有代码变化的情况,1.7和1.8使用了相同的process.waitFor()。
  • 没错,我在评论中忽略了这一点。也许 waitFor() 实现在 1.8 中存在缺陷并以超时调用版本?这听起来像是一个繁琐的简化为最小示例的案例......
【解决方案2】:

您已经描述了症状,但我认为这还不够,如果只是因为不可能在任何地方搜索“java 8 high CPU”之类的东西(谷歌、java bug parade 等) .) 并找到有用的结果。不幸的是,您需要收集有关使用 CPU 的更多信息。以下是有关如何执行此操作的一些想法:

  1. 使用 VisualVM 等工具进行配置文件。负载差异非常大,因此您可能只能发现正在使用 CPU 的内容。
  2. 查找繁忙的线程。您可以拍摄一堆线程快照并进行观察,或者尝试使用 jvmtop 之类的工具。
  3. 通过启用 GC 日志记录或使用 jstat 等工具检查垃圾收集器正在执行的操作。
  4. 使用strace 跟踪系统调用的执行。

【讨论】:

  • 感谢您提供此信息,我将查看这些工具并将收集到的任何结果发回。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-13
  • 2023-01-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多