我很高兴用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");
}
控制台输出:
//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,混合模式)