что скорость работы определяется временем доступа к оперативной памяти,
Да, скорее всего там не в процессоре bottle neck, а в памяти. Поэтому видимо на сервере и работало быстрее, т.к. там была быстрая серверная память.
При программировании на Java есть ещё одна заковыристая проблема быстродействия, связанная со сборщиком мусора. Например, в моём последнем брутфорсере объекты создаются и уничтожаются сотнями тысяч в секунду. По мере накопления отработанных данных вызывается
GC, и это хорошо видно на графике производительности (при решении упомянутого в теме чуть ранее пазла):
Низкие горизонтальные плато как раз соответствуют моментам удаления мусора. Не смотря на то, что сам процесс удаления не самый рациональный (
сборщик мусора должен перебрать все зарегистрированные в Java-окружении объекты и определить на которые из них нет ссылок из используемых в программе объектов), проблема не в самой сборке мусора. Проблема заключается в том, как ведёт себя программа, активно создающая и уничтожающая объекты, когда память Java-окружения подходит к концу. Заканчивается она, разумеется, потому, что созданных и ещё используемых в программе объектов очень много. В этой ситуации сборщику мусора приходится просеивать стог сена (десятки миллионов объектов) в поисках нескольких затерявшихся иголок. Он, конечно, со своей задачей справляется, но очень медленно. А пока он занят, основная работа простаивает. И это, опять же, хорошо видно на графике производительности:
Этот график соответствует случаю, когда пазл сокобана (#21 из оригинальных 60) не разрешим с имеющейся у среды памятью. К концу работы (прерванной вручную) программа всё больше и больше времени (10+ секунд) простаивает, пока работает
GC, что перемежается коротенькими рывками задачу таки решить. При этом программа не завершается с ошибкой
Out of memory, просто потому, что до этого момента ещё далеко как по величине оставшейся памяти (в этом случае больше 10%), так и (в особенности!) по времени. (Заметка: на 250-ой секунде система сделала своп незадействованных процессов в файл подкачки, чтобы освободить оперативку. При этом даже нагрузка на процессор упала, так как Java-среда остановилась).
Чтобы бороться с такими ситуациями и позволить программе завершиться в разумное время (когда станет понятно, что для выполнения задачи выделенной среде памяти не хватит), я вручную отслеживаю загруженность памяти и завершаю работу, когда величина свободного места упадёт ниже некоторого лимита. Обычно это 20% от всего объёма. На втором графике для наглядности я этот лимит понизил до 10%, поэтому мне пришлось в конце концов завершить программу вручную. Соответствующий код выглядит приблизительно так:
public class StateProcessor {
private static final int MEMORY_RESERVE_PERCENT = 20;
private static final int TIME_STEP = 1000;
private static final int ITER_MASK = 8191;
private static final Runtime rt = Runtime .getRuntime ();
// ...
private long startTime, time;
// ...
public void run (boolean priorityType, StateSpace stateSpace) {
long iterCount, nextTime, memoryLimit, memory;
initialize (priorityType, stateSpace);
iterCount = 0;
startTime = System .currentTimeMillis ();
nextTime = startTime + TIME_STEP;
memoryLimit = (long) ((1.0 - MEMORY_RESERVE_PERCENT / 100.0) * rt .maxMemory ());
while (!nodesQueue .isEmpty ()) {
expandState (nodesQueue .remove (), stateSpace);
++iterCount;
if (0 != (iterCount & ITER_MASK)) {
continue;
}
time = System .currentTimeMillis ();
if (nextTime > time) {
continue;
}
nextTime = time + TIME_STEP;
//System .out .println ((time - startTime) + " " + iterCount + " " + stateSpace .getSize ());
memory = rt .totalMemory () - rt .freeMemory ();
if (memoryLimit > memory) {
continue;
}
System .out .println ("Memory limit exceeded: " + memory + " / " + memoryLimit + " / " + rt .maxMemory ());
return;
}
time = System .currentTimeMillis ();
}
// ...
}
Можно, конечно, писать программы так, чтобы создавались только используемые объекты, тогда сборщику мусора нечего будет собирать... но в этом случае придётся шагать по труппам всех концепций ООП, положенных в основу Java. Не говоря о сложности такого написания и его склонности порождать трудновылавливаемые ошибки.