我有一个我不理解的Java性能问题
我写了一些代码来制作一个多维数组,而不是一个数组数组,这样我就可以节省一些内存。然后我运行了一些测试,将其速度与常规Java数组数组(int[][])的速度进行比较,因为我不希望我的程序运行得更慢,即使它节省了一些内存。我在计时测试中看到的让我感到困惑。下面是测试运行的典型结果。时间是针对同一段代码的。请注意,最后两个比前四个大得多。
时间: 58343722 ns
时间: 59451156 ns
时间: 51374777 ns时间: 61777424 ns
时间: 813156695 ns
时间: 782140511 ns
现在我想到的第一件事就是垃圾收集器开始发挥作用。我将内存限制提高到5GB(-Xmx5g),以便垃圾回收器挑衅性地无法启动。一切都没有改变。我四处移动东西,但模式仍然存在。
那么模式是什么呢?在前三次中,代码位在函数中,我调用它三次。在第二个三次中,代码位在单个函数中重复三次。因此,模式是,每当代码位在同一函数中多次运行时,运行该位代码所需的时间将从第二位代码开始飙升,然后一直停留在那里。
我确实发现了一个变化,会产生这样的结果:
时间: 58729424 ns
时间: 59965426 ns
时间: 51441618 ns时间: 57359741 ns
时间: 65362705 ns
时间: 857942387 ns
我所做的是在后三个代码位之间添加一毫秒的延迟。这样做只会加速块中的第二个代码位,并且任何延迟都不会加速之后的任何代码位。
坦率地说,我很困惑。我无法解释这种行为。有人能说明一下正在发生的事情吗?
代码如下:
package multidimensionalarraytests;
import java.lang.reflect.Array;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MultidimensionalArrayTests {
    static ArrayInt2Dv1 array=new ArrayInt2Dv1(10000,10000);
    public static void main(String[] args) {
        System.out.println("ignore the warmup");
        test();
        test();
        combined();
        combined();
        
        System.out.println("running tests");
        test();
        test();
        test();
        System.out.println();
        combined();
    }
    static long test(){
        int value=1;
        long start,stop,time;
        
        System.out.print("time: ");
        start=System.nanoTime();
        for(int x=0;x<array.length1;x++){
            for(int y=0;y<array.length2;y++){
                array.set(x, y, value);
                value=array.get(x, y);
            }   
        }
        stop=System.nanoTime();
        time=(stop-start);
        System.out.println(time+" ns");
        return time;
    }
    static void combined(){
        int value=1;
        long start,stop,time;
        
        System.out.print("time: ");
        start=System.nanoTime();
        for(int x=0;x<array.length1;x++){
            for(int y=0;y<array.length2;y++){
                array.set(x, y, value);
                value=array.get(x, y);
            }   
        }
        stop=System.nanoTime();
        time=(stop-start);
        System.out.println(time+" ns");
        //try {Thread.sleep(1);} catch (InterruptedException ex) {}
        System.out.print("time: ");
        start=System.nanoTime();
        for(int x=0;x<array.length1;x++){
            for(int y=0;y<array.length2;y++){
                array.set(x, y, value);
                value=array.get(x, y);
            }   
        }
        stop=System.nanoTime();
        time=(stop-start);
        System.out.println(time+" ns");
        //try {Thread.sleep(60000);} catch (InterruptedException ex) {}
        System.out.print("time: ");
        start=System.nanoTime();
        for(int x=0;x<array.length1;x++){
            for(int y=0;y<array.length2;y++){
                array.set(x, y, value);
                value=array.get(x, y);
            }   
        }
        stop=System.nanoTime();
        time=(stop-start);
        System.out.println(time+" ns");     
    }
}
和:
package multidimensionalarraytests;
public class ArrayInt2Dv1 {
    int [] array;
    public final int length1;
    public final int length2;
    public ArrayInt2Dv1(int length1, int length2){
        this.length1=length1;
        this.length2=length2;
        array=new int[length1*length2];
    }
    public int get(int x,int y){
        return array[x*length2+y];
    }
    public void set(int x,int y,int value){
        array[x*length2+y]=value;
    }
}
---编辑---
Windows 7 上带有选项的输出 -Xms5g -Xmx5g -XX:+PrintCompilation -verbose:gc -XX:CICompilerCount=1 -Xbatch
time:     299    1    b        multidimensionalarraytests.ArrayInt2Dv1::set (15 bytes)
    302    2    b        multidimensionalarraytests.ArrayInt2Dv1::get (14 bytes)
    303    1 %  b        multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
    358    1 %           multidimensionalarraytests.MultidimensionalArrayTests::test @ -2 (114 bytes)   made not entrant
60671451 ns
    359    3    b        multidimensionalarraytests.MultidimensionalArrayTests::test (114 bytes)
time:     365    2 %  b        multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
58104484 ns
time:     425    3 %  b        multidimensionalarraytests.MultidimensionalArrayTests::combined @ 31 (330 bytes)
69008251 ns
time: 806898159 ns
time: 845447596 ns
   2146    4    b        multidimensionalarraytests.MultidimensionalArrayTests::combined (330 bytes)
time: 52493169 ns
time: 804304528 ns
time: 845500191 ns
running tests
time: 51290771 ns
time: 51922285 ns
time: 51264108 ns
time: 52258679 ns
time: 842229025 ns
time: 871403625 ns
在 Linux 上(Ubuntu 位于同一台计算机上的 VirtualBox 上),具有相同的选项:
    283   1   b   java.lang.String::hashCode (60 bytes)
    285   2   b   sun.nio.cs.UTF_8$Encoder::encodeArrayLoop (490 bytes)
    287   3   b   java.lang.String::charAt (33 bytes)
    287   4   b   java.lang.String::indexOf (151 bytes)
    297   5   b   java.io.UnixFileSystem::normalize (75 bytes)
   2850   6   b   java.lang.String::lastIndexOf (156 bytes)
ignore the warmup
time:    5885   7   b   multidimensionalarraytests.ArrayInt2Dv1::set (15 bytes)
   5948   8   b   multidimensionalarraytests.ArrayInt2Dv1::get (14 bytes)
   5949   1%  b   multidimensionalarraytests.MultidimensionalArrayTests::test @ 31 (114 bytes)
11529998483 ns
  17565   9   b   multidimensionalarraytests.MultidimensionalArrayTests::test (114 bytes)
time: 1619622928 ns
time:   19718   2%  b   multidimensionalarraytests.MultidimensionalArrayTests::combined @ 31 (330 bytes)
475786382 ns
time: 288586857 ns
time: 315560700 ns
  20789  10   b   multidimensionalarraytests.MultidimensionalArrayTests::combined (330 bytes)
time: 460577230 ns
time: 311525066 ns
time: 312343429 ns
running tests
time: 310261854 ns
time: 298826592 ns
time: 304689920 ns
time: 315416579 ns
time: 299473245 ns
time: 290211350 ns