Почему мой алгоритм становится быстрее после выполнения нескольких раз? (Ява)

У меня есть алгоритм решения Sudoku, для которого моя цель - сделать как можно быстрее. Чтобы проверить этот алгоритм, я запускаю его несколько раз и вычисляю среднее значение. Заметив некоторые странные цифры, я решил распечатать все время и получил этот результат:

Execution Time : 4.257746 ms (#1)
Execution Time : 7.610686 ms (#2)
Execution Time : 6.277609 ms (#3)
Execution Time : 7.595707 ms (#4)
Execution Time : 7.610131 ms (#5)
Execution Time : 5.011104 ms (#6)
Execution Time : 3.970937 ms (#7)
Execution Time : 3.923783 ms (#8)
Execution Time : 4.070238 ms (#9)
Execution Time : 4.765347 ms (#10)
Execution Time : 0.818264 ms (#11)
Execution Time : 0.620216 ms (#12)
Execution Time : 0.679021 ms (#13)
Execution Time : 0.643516 ms (#14)
Execution Time : 0.718408 ms (#15)
Execution Time : 0.744481 ms (#16)
Execution Time : 0.760569 ms (#17)
Execution Time : 0.80384 ms (#18)
Execution Time : 0.75946 ms (#19)
Execution Time : 0.802176 ms (#20)
Execution Time : 66.032508 ms : average = 3.3016254000000003

После 10-15 исполнений (оно изменяется случайным образом), производительность алгоритма резко улучшается. Если я запустил его несколько сотен раз, он в конечном итоге стабилизируется примерно на 0,3 мс. Обратите внимание, что я запускаю алгоритм один раз перед этим циклом для JIT, чтобы сделать это.

Кроме того, если я заставляю поток спать в течение 2 секунд перед запуском моего цикла, все мои времена равны 1 мс (+/- 0,2).

Кроме того, если я решил общий Судоку (сетка с 1-9 по диагонали) примерно 500 раз перед моей петлей, все мои времена составляют около 0,3 мс (+/- 0,02).

Каждое решение идентично. Все значения reset.

Итак, мой вопрос многократно:

-Почему каждый раз решающее время улучшается после последовательных решеток?

-Почему у меня внезапное падение времени решения после решения 10-15?

Ответ 1

Это связано с тем, что JIT компилирует этот метод после JVM делает определенное количество частых вызовов этого метода. На практике методы не компилируются при первом вызове. Для каждого метода JVM поддерживает подсчет вызовов, который увеличивается каждый раз при вызове метода. JVM интерпретирует метод, пока его количество вызовов не превысит JIT compilation threshold. Когда количество вызовов достигает порога, JIT компилирует и оптимизирует bytecodes, чтобы он работал быстрее, когда в следующий раз его вызывают JVM. Поэтому в вашем случае производительность алгоритма резко возрастает после каждых 10-15 (случайных) исполнений.

Ответ 2

Скорее всего - JVM оптимизировал свое выполнение после нескольких запусков.

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

Не зная подробно, что вы запускаете, трудно сказать что-то более точно.

Используете ли вы внешние ресурсы - соединения с базами данных, очереди/темы JMS и т.д.? Вы используете кеширование?

Все, что имеет значение...