3

我们有一个简单的单元测试作为我们的性能测试套件的一部分,我们使用它来验证基本系统是否正常并且在我们开始测试代码之前执行。这样我们通常会验证一台机器是否适合运行实际的性能测试。

当我们使用此测试比较 Java 6 和 Java 7 时,Java 7 的执行时间要长得多!我们看到 Java 6 的平均时间为 22 秒,Java 7 的平均时间为 24 秒。该测试只计算斐波那契,因此这里应该只与单线程中的字节码执行相关,而不是 I/O 或其他任何东西。

目前,我们在带有或不带有“-server”的 Windows 上使用默认设置运行它,同时使用 32 位和 64 位 JVM,所有运行都表明 Java 7 的类似降级。

哪些调优选项可能适合在这里尝试将 Java 7 与 Java 6 匹配?

public class BaseLinePerformance {

    @Before
    public void setup() throws Exception{
        fib(46);
    }

    @Test
    public void testBaseLine() throws Exception {
        long start = System.currentTimeMillis();
        fib(46);
        fib(46);
        System.out.println("Time: " + (System.currentTimeMillis() - start));
    }

    public static void fib(final int n) throws Exception {
        for (int i = 0; i < n; i++) {
            System.out.println("fib(" + i + ") = " + fib2(i));
        }
    }

    public static int fib2(final int n) {
        if (n == 0)
            return 0;
        else if (n == 1)
            return 1;
        else
            return fib2(n - 2) + fib2(n - 1);
    }
}

更新:我已将测试减少为不进行任何睡眠,并遵循如何在 Java 中编写正确的微基准测试中的其他建议?,我仍然看到 Java 7 和 Java 6 之间的相同差异,打印编译和 GC 的附加 JVM 选项在实际测试期间不显示任何输出,仅打印初始编译信息。

4

2 回答 2

5

经过一番挖掘,我的一位同事发现了这个原因:

有一个 JVM 标志 -XX:MaxRecursiveInlineLevel 的默认值为 1。在以前的版本中,这个设置的处理似乎有点不正确,所以 Sun/Oracle 在 Java 7 中“修复”了这个,但是它有副作用有时现在的内联不太积极,因此递归代码的纯运行时/CPU时间可能比以前更长。

我们正在测试将其设置为 2 以获得与 Java 6 中相同的行为,至少对于相关测试而言。

于 2013-09-10T14:52:04.483 回答
0

这不是一个简单的答案,有很多事情可以解释这 2 秒。

对于您的评论,我假设您已经熟悉微基准测试,并且您的基准测试在预热 JVM 后运行,您的代码达到优化的 JIT 状态并且没有发生 GC,同时假设您的硬件设置没有改变。

我建议您对基准进行 CPU 分析,这将帮助您确定这两秒的计算位置并可能采取相应的行动。

如果您对字节码感到好奇,可以看一看。

为此,您可以编译您的类并在两台机器上执行 javap -c ClassName,这将反汇编类文件字节码并将其显示给您,在这里您肯定会看到两个编译类之间的变化。

总之,在查看数据后相应地分析和调整您的应用程序以达到 22 秒,对于字节码实现,无论如何您都无能为力。

于 2013-09-04T05:40:48.133 回答