Каково реальное время выполнения метода в Java и от чего оно зависит? - PullRequest
0 голосов
/ 17 февраля 2012

У меня есть одна проблема, которую я не могу объяснить. Вот код в основной функции:

String numberStr = "3151312423412354315";

System.out.println(numberStr + "\n");
System.out.println("Lehman method: ");
long beginTime = System.currentTimeMillis();
System.out.println(Lehman.getFullFactorization(numberStr));
long finishTime = System.currentTimeMillis();
System.out.println((finishTime-beginTime)/1000. + " sec.");

System.out.println();

System.out.println("Lehman method: ");
beginTime = System.currentTimeMillis();
System.out.println(Lehman.getFullFactorization(numberStr));
finishTime = System.currentTimeMillis();
System.out.println((finishTime-beginTime)/1000. + " sec.");

Если необходимо: метод Lehman.getFullFactorization(...) возвращает ArrayList простых делителей в формате String.

Вот вывод:

3151312423412354315

Lehman method: 
[5, 67, 24473, 384378815693]
0.149 sec.

Lehman method: 
[5, 67, 24473, 384378815693]
0.016 sec.

Я был удивлен, когда увидел это. Почему второе выполнение того же метода намного быстрее, чем первое? Во-первых, я подумал, что при первом запуске метода он вычисляет время со временем запуска JVM и его ресурсов, но это невозможно, поскольку очевидно, что JVM запускается до выполнения «основного» метода.

Ответы [ 5 ]

2 голосов
/ 17 февраля 2012

В некоторых случаях JIT-компилятор Java (см. http://java.sun.com/developer/onlineTraining/Programming/JDCBook/perf2.html#jit) запускает первое выполнение метода и выполняет оптимизацию кода этого метода. Это должно ускорить все последующие выполнения. что происходит в вашем случае.

1 голос
/ 17 февраля 2012

Попробуйте сделать это более 10000 раз, и это будет намного быстрее.Это связано с тем, что сначала необходимо загрузить код (дорого), затем запустить в интерпретируемом режиме (нормально, скорость) и, наконец, скомпилировать в собственный код (гораздо быстрее)

Можете ли вы попробовать это?

int runs = 100*1000;
for(int i = -20000 /* warmup */; i < runs; i++) {
   if(i == 0)
       beginTime = System.nanoTime();
   Lehman.getFullFactorization(numberStr);
}
finishTime = System.nanoTime();
System.out.println("Average time was " + (finishTime-beginTime)/1e9/runs. + " sec.");
0 голосов
/ 17 февраля 2012

Я предполагаю, что он сохранен в кэш-памяти L1 / L2 на ЦП для оптимизации.

Или Java не нужно интерпретировать это снова и вызывает его из памяти как уже скомпилированный код.

0 голосов
/ 17 февраля 2012

Есть две вещи, которые заставляют второй бежать быстрее.

  1. В первый раз класс, содержащий метод, должен быть загружен. Второй раз он уже в памяти.
  2. Самое главное, JIT оптимизирует код, который часто выполняется: во время первого вызова JVM начинает с интерпретации байтового кода, затем компилирует его в машинный код и продолжает выполнение. Во второй раз код уже скомпилирован.

Вот почему микро-тесты в Java часто трудно проверить.

0 голосов
/ 17 февраля 2012

Полагаю, JVM кэшировала результаты (может быть, в частности) первого вычисления, и вы наблюдаете более быстрое второе вычисление.JIT в действии.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...