Могу ли я повторить некоторые из оптимизаций, выполненных JVM вручную? - PullRequest
3 голосов
/ 31 мая 2010

Я работаю над решением судоку в школе, и у нас небольшой конкурс производительности. Прямо сейчас мой алгоритм довольно быстр при первом запуске (около 2,5 мс), но еще быстрее, когда я решаю одну и ту же головоломку 10 000 раз (около 0,5 мс за каждый прогон). Конечно, эти сроки зависят от решаемой головоломки. Я знаю, что JVM выполняет некоторую оптимизацию, когда метод вызывается несколько раз, и я подозреваю, что это происходит.

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

Примечание: компиляция в нативный код невозможна

Спасибо!

Редактировать: Все эти параметры виртуальной машины хороши, но на самом деле не являются «законными» в конкурсе алгоритмов, поскольку каждый может использовать эти параметры и получить повышение производительности. Я ищу оптимизацию кода.

Ответы [ 9 ]

3 голосов
/ 31 мая 2010

Существует множество микрооптимизаций, которые вы можете применить к своему коду. Эта статья JavaWorld дает обзор. Больше идей можно найти на этой странице .

Хотя я бы не ожидал от этого большого выигрыша. Если вы больше не можете оптимизировать свои алгоритмы, попробуйте оптимизировать свои структуры данных для легкого доступа и использования локальности кэша.

2 голосов
/ 31 мая 2010

Если у вас может быть «разминка» для получения JIT для компиляции игровых классов, вы можете добавить опции

-XX:CompileThreshold=20

Чтобы быть уверенным, что большинство горячих точек компилируются при первом запуске. Последующие прогоны будут выполняться без какой-либо дополнительной (или очень небольшой) компиляции.

См

1 голос
/ 31 мая 2010

tl; dr : нет, большинство оптимизаций, выполняемых JVM, не могут быть выражены в байт-коде Java.

По своей природе байт-код Java определяет ваш код на очень высоком уровне.

Это задуманно и является одной из причин, по которой JVM может выполнить все эти оптимизации: байт-код описывает операции на относительно высоком уровне и оставляет фактические детали выполнения JVM.

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

Например, спецификация JVM указывает, что каждый доступ к массиву, превышающий границы массива, должен выдавать ArrayIndexOutOfBoundsException (см. VM Spec 2.5.14 ).

Однако умная JVM может оптимизировать многие из этих проверок, если она знает, что они уже произошли (например, при итерации по массиву, JVM может фактически выполнить проверку границ перед итерацией и пропустить ее во время каждой итерации ).

Эта оптимизация просто не может быть выражена с помощью байтового кода , потому что проверка границ неявная и нельзя избежать в байте коды, представляющие доступ к массиву.

1 голос
/ 31 мая 2010

Вы можете попытаться уменьшить доступную память кучи, чтобы сборщик мусора быстрее прогревался. Требуется некоторое время, прежде чем управление памятью будет работать в «нормальных» условиях, и сокращение объема памяти может ускорить его.

0 голосов
/ 31 мая 2010

Ну, вот некоторые хитрости, которые вы могли бы попробовать:

1) Снижение прочности, например, вместо деления на 2 вы можете просто использовать сдвиг вправо

int i = 10 / 2;  // division by 2
i     = 10 >> 1; // does the same

2) Используйте примитивные типы вместо ссылочных типов, например, int over Integer

3) Предпочитать массивы коллекциям

4) Используйте составные операторы, например, я + = 2 вместо i = i + 2

5) Счетчик зацикливается, а не вверх, например

for (int i = 10; i >= 0; i--) {
    System.out.println(i);
}

(only useful if you can compare against zero)

6) Используйте ключевое слово final для переменных экземпляра, если это возможно

0 голосов
/ 31 мая 2010

Я знаю, что это не то, что вы ищете, но я бы оспаривал методологию конкурса (предполагая, что это так). Все основные тесты (SPEC и т. Д.) Явно учитывают период прогрева (часто несколько минут), чтобы обеспечить измерение самой рабочей нагрузки, а не временные эффекты, такие как JIT-компиляция и т. Д. *

Кроме того, обратите внимание, что то, что работает в 2,5 мс, не имеет смысла на стенде - многие JVM в ОС, таких как Windows, не так хорошо измеряют время, используя такие вещи, как System.currentTimeMillis (). Вам нужно будет повторять это много раз, чтобы иметь смысл ... Я бы посоветовал в диапазоне от 30 до 60-х годов стать достаточно статистически значимым.

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

0 голосов
/ 31 мая 2010

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

Я рекомендую дважды проверить ваш алгоритм, прежде чем слишком интенсивно искать другие оптимизации;)

0 голосов
/ 31 мая 2010

JVM работает с JIT (Just-In-Time) компилятором: он компилирует байт-код Java в машинный код на лету. Он делает много сложного анализа, чтобы определить, когда и что компилировать в нативный код. Одна из вещей, на которую он смотрит, - это код, который запускается более одного раза - если вы выполняете какой-то фрагмент кода 10.000 раз, как вы это делаете, JVM, скорее всего, решит, что выгодно скомпилировать его в нативный код, а затем запустить что каждый раз, когда код выполняется снова.

Насколько я знаю, вы не можете контролировать, когда JVM делает это. ( edit : может быть не так, как указывает mdma в своем ответе - есть несколько расширенных опций -XX).

У Sun есть две версии JVM: клиентская JVM, которая настроена для быстрого запуска, но менее агрессивной оптимизации, и серверная JVM, которая имеет более медленное время запуска, но которая выполняет более агрессивные оптимизации.

Вы можете попробовать запустить вашу программу с сервером JVM:

java -server com.mypackage.MyProgram

Обратите внимание, что, насколько мне известно, только 64-разрядная версия Sun Java для Windows включает сервер JVM.

0 голосов
/ 31 мая 2010

Вы можете форсировать сборку мусора перед «тяжелыми» действиями, такими как основной цикл, вызывая `System.gc (); '

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