为什么重复的代码段在循环中运行得更快而在Java中显式重复?

时间:2016-04-21 21:37:32

标签: java performance benchmarking

我很高兴用Java测试一些代码,并且由于我计算了不同的代码段,我遇到了一个奇怪的行为。在循环内重复一段简单的代码,例如10次,明显快于将相同的段复制粘贴10次: 请注意,我遵循了此帖子中有关benchmarking in Java的建议,此代码使用参数-XX:+PrintCompilation-verbose:gc运行。

//here max i = 3 (for shorter code), but I actually ran it with max i = 10
public static void main(String[] args) {
    final long[] list1 = new long[100000000];
    Random r = new Random();
    long time;

    for(int i = 0 ; i < list1.length ; i++) list1[i] = r.nextLong();

    System.out.println("\n\nInitialization Done\n\n");

    for(int i = 0 ; i < 3 ; i++) {
        System.out.println("###Start###");
        time = System.nanoTime();
        for(long l : list1) {long n = l*65356;}
        System.out.println("Time:\t" + (System.nanoTime()-time) + "\t");
        System.out.println("####End####\n");
    }

    System.out.println("\n\nLoop Done\n\n");

    System.out.println("###Start###");
    time = System.nanoTime();
    for(long l : list1) {long n = l*65356;}
    System.out.println("Time:\t" + (System.nanoTime()-time) + "\t");
    System.out.println("####End####\n");

    System.out.println("###Start###");
    time = System.nanoTime();
    for(long l : list1) {long n = l*65356;}
    System.out.println("Time:\t" + (System.nanoTime()-time) + "\t");
    System.out.println("####End####\n");

    System.out.println("###Start###");
    time = System.nanoTime();
    for(long l : list1) {long n = l*65356;}
    System.out.println("Time:\t" + (System.nanoTime()-time) + "\t");
    System.out.println("####End####\n");
}

以下是图表中的惊人结果:
enter image description here

控制台输出:

//I removed a whole bunch of initialization before this point
Initialization Done


###Start###
   2926   32 %     3       EmptySlate::main @ 76 (1049 bytes)
   2933   33 %     4       EmptySlate::main @ 76 (1049 bytes)
   2935   32 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2935   33 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   9570242 
####End####

###Start###
   2936   34 %     3       EmptySlate::main @ 76 (1049 bytes)
   2945   35 %     4       EmptySlate::main @ 76 (1049 bytes)
   2951   34 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   15950404    
####End####

###Start###
Time:   893 
####End####
   2952 
  36       1       java.nio.Buffer::position###Start### (5 bytes)

Time:   446 
####End####

###Start###   2952   37       1       java.nio.Buffer::limit
 (5 bytes)
Time:   892 
####End####

###Start###
Time:   447 
####End####

###Start###
Time:   446 
####End####

###Start###
Time:   446 
####End####

###Start###
Time:   447 
####End####

###Start###   2952   38       3       java.nio.ByteBuffer::arrayOffset (35 bytes)

Time:   1785    
####End####

Loop Done

###Start###
   2952   35 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2952   39       3       java.nio.Buffer::position (43 bytes)
   2952   40 %     3       EmptySlate::main @ 183 (1049 bytes)
   2961   41 %     4       EmptySlate::main @ 183 (1049 bytes)
   2963   40 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2963   41 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10607276    
####End####

###Start###
   2963   43 %     3       EmptySlate::main @ 272 (1049 bytes)
   2972   42       3       java.nio.CharBuffer::arrayOffset (35 bytes)
   2972   44 %     4       EmptySlate::main @ 272 (1049 bytes)
   2975   43 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2975   44 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   11731769    
####End####

###Start###
   2975   45 %     3       EmptySlate::main @ 361 (1049 bytes)
   2983   46 %     4       EmptySlate::main @ 361 (1049 bytes)
   2985   45 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2985   46 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10467160    
####End####

###Start###
   2985   47 %     3       EmptySlate::main @ 450 (1049 bytes)
   2994   48 %     4       EmptySlate::main @ 450 (1049 bytes)
   2996   47 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   2996   48 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10436370    
####End####

###Start###
   2996   49 %     3       EmptySlate::main @ 539 (1049 bytes)
   3005   50 %     4       EmptySlate::main @ 539 (1049 bytes)
   3007   49 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3007   50 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10839760    
   3007   51 ####End####
      3      
 java.lang.String::getChars (62 bytes)
###Start###
   3007   52 %     3       EmptySlate::main @ 628 (1049 bytes)
   3015   53 %     4       EmptySlate::main @ 628 (1049 bytes)
   3017   52 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3017   53 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10452435    
####End####

###Start###
   3018   54 %     3       EmptySlate::main @ 717 (1049 bytes)
   3026   55 %     4       EmptySlate::main @ 717 (1049 bytes)
   3028   54 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3028   55 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10427892    
####End####

###Start###
   3028   56 %     3       EmptySlate::main @ 806 (1049 bytes)
   3037   57 %     4       EmptySlate::main @ 806 (1049 bytes)
   3039   56 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3039   57 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10888399       3039   58       3       java.util.Arrays::copyOfRange (63 bytes)

####End####

###Start###
   3040   60 %     3       EmptySlate::main @ 895 (1049 bytes)
   3048   59       3       java.nio.charset.CoderResult::isUnderflow (13 bytes)
   3048   61 %     4       EmptySlate::main @ 895 (1049 bytes)
   3050   60 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3050   61 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   11396206    
####End####

###Start###
   3051   63 %     3       EmptySlate::main @ 984 (1049 bytes)
   3059   62       3       java.nio.ByteBuffer::array (35 bytes)
   3059   64 %     4       EmptySlate::main @ 984 (1049 bytes)
   3061   63 %     3       EmptySlate::main @ -2 (1049 bytes)   made not entrant
   3061   64 %     4       EmptySlate::main @ -2 (1049 bytes)   made not entrant
Time:   10975860    
####End####

在循环中,无论循环总数如何,前两个循环都明显变慢,然后从循环3开始几乎没有任何变化。然而,显式代码在相同值处保持大部分稳定。

我已经以相反的顺序尝试了它(先显式重复),循环次数不同,我得到了相同的结果。

我想也许是编译器&#34;只需要准备&#34;一次循环,不必初始化&#34;在每次迭代中,但为什么第二个循环始终更慢,并且只在第3个周期加速?我想也许它与CPU缓存数组有关,但是预计显式代码也会受到影响。

我的问题是为什么看似独立且等效的代码段在重复使用循环与显式重复时运行得更快?差异是基于编译器还是硬件级别?

CPU:Intel Core i7-3610QM @ 2.3GHz

Java版本:1.8.0_45
Java(TM)SE运行时环境(版本1.8.0_45-b14)
Java HotSpot(TM)64位服务器VM(版本25.45-b02,混合模式)

0 个答案:

没有答案