java - 第一次 Java 循环运行缓慢,为什么? [Sun 热点 1.5,sparc]

标签 java performance jvm-hotspot microbenchmark

在 Solaris SPARC 机器上对一些 Java 代码进行基准测试时,我注意到我第一次调用基准函数时它运行得非常慢(相差 10 倍):

  • 首先 | 1 | 25295.979 毫秒
  • 第二 | 1 | 2256.990 毫秒
  • 第三 | 1 | 2250.575 毫秒

这是为什么?我怀疑是 JIT 编译器,有什么方法可以验证吗?

编辑:鉴于一些答案,我想澄清一下这段代码是最简单的 我可以找到展示这种行为的可能测试用例。所以我的目标不是得到 它运行得很快,但要了解发生了什么,这样我才能在我的真实世界中避免它 基准。

已解决:Tom Hawtin 正确地指出我的“SLOW”时间实际上是合理的。 根据这一观察,我将调试器附加到 Java 进程。在第一个过程中,内部循环看起来像这样:

0xf9037218:     cmp      %l0, 100
0xf903721c:     bge,pn   %icc,0xf90371f4        ! 0xf90371f4
0xf9037220:     nop
0xf9037224:     ld       [%l3 + 92], %l2
0xf9037228:     ld       [%l2 + 8], %l6
0xf903722c:     add      %l6, 1, %l5
0xf9037230:     st       %l5, [%l2 + 8]
0xf9037234:     inc      %l0
0xf9037238:     ld       [%l1], %g0
0xf903723c:     ba,pt    %icc,0xf9037218        ! 0xf9037218

在接下来的迭代中,循环看起来像这样:

0xf90377d4:     sub      %l2, %l0, %l3
0xf90377d8:     add      %l3, %l0, %l2
0xf90377dc:     add      %l2, 1, %l4
0xf90377e0:     inc      %l0
0xf90377e4:     cmp      %l0, 100
0xf90377e8:     bl,pn    %icc,0xf90377d8        ! 0xf90377d8

因此 HotSpot 从内部循环中移除了内存访问,将速度提高了一个数量级。

类(class):做数学题!我应该自己完成 Tom 的计算。

基准 Java 代码:

    private int counter;
    private int nThreads;

    private void measure(String tag) throws Exception {
            MyThread threads[] = new MyThread[nThreads];
            int i;

            counter = 0;

            for (i = 0; i < nThreads; i++)
                    threads[i] = new MyThread();

            long start = System.nanoTime();

            for (i = 0; i < nThreads; i++)
                    threads[i].start();

            for (i = 0; i < nThreads; i++)
                    threads[i].join();

            if (tag != null)
                    System.out.format("%-20s | %-2d | %.3f ms \n", tag, nThreads,
                                     new Double((System.nanoTime() - start) / 1000000.0));
    }
    public MyBench() {
            try {
                    this.nThreads = 1;
                    measure("First");
                    measure("Second");
                    measure("Third");
            } catch (Exception e) {
                    System.out.println("Error: " + e);
            }
    }

    private class MyThread extends Thread {
            public void run() {
                    while (counter < 10000000) {
                            // work
                            for (int j = 0; j < 100; j++)
                                    counter++;
                            counter -= 99;
                    }
            }
    }

最佳答案

一些丑陋的、不切实际的代码(微基准测试的东西):

                while (counter < 10000000) {
                        // work
                        for (int j = 0; j < 100; j++)
                                counter++;
                        counter -= 99;
                }

那么它在做什么以及它应该运行多快。

内部循环将计数器递增 100 次,然后计数器递减 99。因此递增 1。注意计数器是外部类的成员变量,因此会有一些开销。然后运行 ​​10,000,000 次。所以内部循环运行了 1,000,000,000 次。

一个使用访问器方法的循环,称之为 25 个循环。 1 GHz 下 1,000,000,000 次,给出 25 秒。

嘿,我们预测了SLOW时间。慢的时间很快。快速时间是在基准以某种方式被打破之后——2.5 个周期迭代?使用 -server,您可能会发现它变得更加愚蠢。

关于java - 第一次 Java 循环运行缓慢,为什么? [Sun 热点 1.5,sparc],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/860231/

相关文章:

c# - 当您已经相当了解 C# 时,还值得学习 Java 吗?

java - 二叉树——中序遍历找位置

java - 提取实体保存类

java - 如何避免重复请求?

javascript - 提高网站性能

javascript - 嵌套的 If/Else 比 Else If 有什么优势吗?

c++ - 在 "loop unrolling"中,所有展开的表达式都被执行了吗?

java - 为什么 jmap -permstat 会报告超过使用的 MaxPermSize 字节数?

java - JVM 在 CompilerThread 崩溃

java - Java libjli 库有什么用?