Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/364.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
第一次Java循环运行缓慢,为什么?[太阳热点1.5,sparc]_Java_Performance_Jvm Hotspot_Microbenchmark - Fatal编程技术网

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

第一次Java循环运行缓慢,为什么?[太阳热点1.5,sparc],java,performance,jvm-hotspot,microbenchmark,Java,Performance,Jvm Hotspot,Microbenchmark,在Solaris SPARC机器上对一些Java代码进行基准测试时,我注意到,第一次调用基准测试函数时,它的运行速度非常慢(相差10倍): 第一个| 1 | 25295.979毫秒 第二个| 1 | 2256.990毫秒 第三个| 1 | 2250.575毫秒 为什么会这样?我怀疑是JIT编译器,有没有办法验证这一点 编辑:根据一些答案,我想澄清这段代码是最简单的 可能的测试案例,我可以找到展示这种行为。所以我的目标不是 它需要跑得快,但要了解发生了什么,这样我才能在真实的生活中避免它 基准

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

  • 第一个| 1 | 25295.979毫秒
  • 第二个| 1 | 2256.990毫秒
  • 第三个| 1 | 2250.575毫秒
为什么会这样?我怀疑是JIT编译器,有没有办法验证这一点

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

解决:汤姆·霍丁正确地指出我的“慢”时间实际上是合理的。 根据这一观察,我向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
public MyBench() {
    try {
        this.nThreads = 1;
        new Mark1();
        measure("First");
        new Mark2();
        measure("Second");
        new Mark3();
        measure("Third");
        new Mark4();
    } catch (Exception e) {
        System.out.println("Error: " + e);
    }
}

private static class Mark1 {
}
private static class Mark2 {
}
private static class Mark3 {
}
private static class Mark4 {
}
在以下迭代中,循环如下所示:

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
public MyBench() {
    try {
        this.nThreads = 1;
        new Mark1();
        measure("First");
        new Mark2();
        measure("Second");
        new Mark3();
        measure("Third");
        new Mark4();
    } catch (Exception e) {
        System.out.println("Error: " + e);
    }
}

private static class Mark1 {
}
private static class Mark2 {
}
private static class Mark3 {
}
private static class Mark4 {
}
因此,HotSpot从内部循环中删除了内存访问,将其速度提高了一个数量级

课程:做数学题!我应该自己做汤姆的计算

基准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;
                    }
            }
    }
专用整数计数器;
私人阅读;
私有void度量值(字符串标记)引发异常{
MyThread线程[]=新的MyThread线程[];
int i;
计数器=0;
对于(i=0;i
这是一个有趣的问题。我怀疑JIT编译器,但以下是我的数字:

First | 1 | 2399.233 ms Second | 1 | 2322.359 ms Third | 1 | 2408.342 ms 第一个| 1 | 2399.233毫秒 第二个| 1 | 2322.359毫秒 第三个| 1 | 2408.342毫秒
可能Solaris正在用线程做一些有趣的事情;你试过使用nThreads=10左右吗?

这是工作中的热点编译器。AFAIK,第一次运行函数时,运行“解释”并分析执行路径,然后JIT编译器可以优化后续函数调用

将类加载添加为可疑对象。类在第一次引用时被延迟加载。因此,代码第一次运行时,您可能是第一次引用某些类。

我建议您使用nThread=Runtime.getRuntime().availableProcessors(),这将为您提供使用系统中所有核心的最佳线程数


您可以尝试关闭JIT,看看它有什么不同。

它肯定是热点编译器。如果您在64位solaris上运行,它默认为服务器VM和hotspot,只需在第一次执行时开始优化即可。在客户端VM上,在热点启动之前,代码可能需要运行几次。(我相信solaris只有服务器vm,但我可能错了)

您可以让vm记录有关类加载和编译的信息,请尝试以下vm参数: -XX:+打印编译 -XX:+TraceClassLoading 这可能会为引擎盖下发生的事情提供进一步的线索

编辑:我不确定这些选项在Java1.5中是否有效(我在1.6中使用过它们)。我会试着检查一下。。。
再次编辑:它在java 1.5中工作(请注意,您需要+,而不是-,或者关闭选项…

有关启动器如何在客户端和服务器VM之间进行选择的信息,请参见,以及不同处理器和操作系统上支持的功能。

验证JIT编译器是否是后续迭代中加速的原因的最佳方法是在JIT编译器关闭的情况下运行基准测试。为此,请指定系统属性
java.compiler=NONE
(单词“NONE”必须为大写)

花费在类加载上的时间也会导致基准代码在第一次运行时运行变慢。最后,在调用Thread.start()和调用线程的run()方法之间存在不确定的延迟


<>你可能想考虑找到一个基准框架。一个好的框架将通过运行几个迭代来“预热”代码,然后使用不同的迭代次数进行多次计时。请参阅。

我相信您也可以使用-Xint的java命令的非标准选项来禁用HotSpot,并仅对代码进行解释。这至少可以让HotSpot从解释时间的等式中消失。

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

while(计数器<10000000){
//工作
对于(int j=0;j<100;j++)
计数器++;
计数器-=99;
}
那么这是在做什么,它应该以多快的速度运行

内环使计数器递增100倍,然后计数器递减99倍。因此,增量为1。注意:计数器是外部类的成员变量,因此存在一些开销。然后运行10000000次。所以内心
[Loaded MyBench$Mark3 from file:/D:/DEVEL/Test/classes/]
Third                | 1  | 2093,659 ms