2016-02-16 3 views
1

позволяет взглянуть на следующие методы два Java:массив доступа через массив потери производительности огромный

static void performance1() { 
    int a=0; 
    int b=0; 
    int[] arrayA = { 3, 4, 5 }; 
    int[] arrayB = { 4, 5, 6, 3, 4, 5, 6, 7, 8, 4 }; 
    long start = System.currentTimeMillis(); 
    for (int i = 0; i < 100000000; i++) { 
     for (int k = 0; k < 100; k++) { 
      a = arrayA[2]; 
      b = arrayB[1]; 
     } 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println(end - start); 

} 

static void performance2() { 
    int a=0; 
    int b=0; 
    int[] arrayA = { 3, 4, 5 }; 
    int[] arrayB = { 4, 5, 6, 3, 4, 5, 6, 7, 8, 4 }; 
    long start = System.currentTimeMillis(); 
    for (int i = 0; i < 100000000; i++) { 
     for (int k = 0; k < 100; k++) { 
      b = arrayB[arrayA[2]]; 
     } 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println(end - start); 

} 

Первый метод занимает 209 мс для выполнения на моей системы, seccond 4295! так что в 20 раз больше. Как это может быть? Насколько я могу видеть это я могу получить прирост производительности 20time если я объявляю 3 раздельные переменные вместо Arraya, потому что следующий метод выполняется очень быстро снова:

static void performance3() { 
    int a=0; 
    int b=0; 
    int[] arrayA = { 3, 4, 5 }; 
    int[] arrayB = { 4, 5, 6, 3, 4, 5, 6, 7, 8, 4 }; 
    long start = System.currentTimeMillis(); 
    for (int i = 0; i < 100000000; i++) { 
     for (int k = 0; k < 100; k++) { 
      b = arrayB[a]; 
     } 
    } 
    long end = System.currentTimeMillis(); 
    System.out.println(end - start); 

} 

Am я с видом что-то очевидное здесь? мне действительно кажется удивительным, что разница настолько велика. Спасибо в любом случае за разъяснениями :)

+1

В первом методе вы всегда получаете доступ к тем же элементам, поэтому компилятор, скорее всего, оптимизирует это. Во втором методе компилятор не может оптимизировать доступ к 'arrayB', так как он не знает индекс во время компиляции (поскольку он может меняться во время выполнения). – Thomas

+0

Вы понимаете, что 'arrayB [a]' всегда 'arrayB [0]'? –

+0

Я просто запустил свой код на своей машине, и все методы так же длится, поэтому, возможно, это что-то еще. Какой JDK вы используете? Как вы их называете? – Thomas

ответ

1

В первом коде всегда устанавливается на 5 и б 5, независимо от того, что ваши показатели петлевые, поэтому компилятор устранил петли полностью, так что на самом деле в конечном итоге что-то вроде:

int a=0; 
int b=0; 
int[] arrayA = { 3, 4, 5 }; 
int[] arrayB = { 4, 5, 6, 3, 4, 5, 6, 7, 8, 4 }; 
long start = System.currentTimeMillis(); 
a = 5; 
b = 5; 
long end = System.currentTimeMillis(); 
System.out.println(end - start); 
+0

, это он вам спасибо :) не получил его первым, потому что вы получаете некоторое увеличение времени, если вы сделаете цикл достаточно большим, но теперь, если я добавлю нуль, это займет одно и то же время. – Nellieder

1

Когда вы b = arrayB[1]; это напрямую ссылается на значение, хранящееся в месте 1 но когда вы делаете b = arrayB[arrayA[2]]; он должен сначала получить значение arrayA[2], а затем получить значение arrayB[] на основе значения извлечения в предыдущий шаг.

Компилятор достаточно умен, чтобы оптимизировать активность на первом шаге, но не на втором этапе.

Будет более понятным, если вы посмотрите на байтовый код, созданный этими двумя методами.

+0

ОК, я понимаю, что он должен быть медленнее, но я ожидал чего-то вроде, может быть, фактора 2 и, безусловно, не фактора 20-40 – Nellieder

+2

@Nellieder Почему вы так думаете? –

+0

Еще одна причина увеличения производительности: в нижнем коде могут появляться побочные эффекты во время выполнения, такие как исключения, в то время как в верхнем коде эти побочные эффекты могут быть оценены до начала цикла. – Ferrybig

Смежные вопросы