Оптимизация обработки и управления большими массивами данных Java - PullRequest
1 голос
/ 08 января 2011

Я пишу довольно интенсивный процессор, параллельный числовой код, который будет обрабатывать большие объемы данных, хранящихся в массивах Java (например, много двойных [100000] с).Некоторые из алгоритмов могут выполняться миллионы раз в течение нескольких дней, поэтому достижение максимальной производительности в стационарном режиме является высоким приоритетом.

По сути, каждый алгоритм является объектом Java, который имеет API метода, похожий на:

   public double[] runMyAlgorithm(double[] inputData);

или, альтернативно, в массив можно передать ссылку для хранения выходных данных:

   public runMyAlgorithm(double[] inputData, double[] outputData);

Учитывая это требование, я пытаюсь определить оптимальную стратегию для выделения / управления пространством массива,Часто алгоритмам требуется большое количество места для временного хранения.Они также будут принимать большие массивы в качестве входных данных и создавать большие массивы в качестве выходных.

Среди вариантов, которые я рассматриваю:

  • Всегда выделяйте новые массивы как локальные переменные, когда они необходимынапример, новый двойной [100000]).Вероятно, самый простой подход, но он создаст много мусора.
  • Предварительно выделите временные массивы и сохраните их как конечные поля в объекте алгоритма - большой недостаток будет в том, что это будеттолько один поток может запускать алгоритм в любой момент времени.
  • Храните предварительно выделенные временные массивы в хранилище ThreadLocal, чтобы поток мог использовать фиксированный объем пространства временного массива всякий раз, когда это необходимо.ThreadLocal потребуется, так как несколько потоков будут запускать один и тот же алгоритм одновременно.
  • Передавать множество массивов в качестве параметров (включая временные массивы для используемого алгоритма).Не очень хорошо, так как это сделает API алгоритма крайне уродливым, если вызывающая сторона должна отвечать за предоставление временного пространства массива ....
  • Выделить очень большие массивы (например, double [10000000]), но также предоставить алгоритмусмещает в массив, так что разные потоки будут использовать разные области массива независимо.Очевидно, потребуется некоторый код для управления смещениями и распределением диапазонов массивов.

Есть мысли о том, какой подход будет наилучшим (и почему)?

Ответы [ 2 ]

2 голосов
/ 08 января 2011

Выделение больших массивов относительно дешево для GC.Вы склонны использовать свое пространство Eden быстро, но стоимость в основном зависит от объекта.Я предлагаю вам написать код как можно проще и оптимизировать его позже после профилирования приложения.двойной [100000] меньше, чем МБ, и вы можете более тысячи в ГБ.

Память намного дешевле, чем раньше.Сервер на 8 ГБ стоит около 850 фунтов стерлингов.Сервер на 24 ГБ стоит около 1800 фунтов стерлингов.(машина на 24 ГБ может позволить вам 24K x double [100000]). Вы можете обнаружить, что использование большого размера кучи или даже большого размера Eden обеспечивает необходимую эффективность.

2 голосов
/ 08 января 2011

При работе с памятью на Java я заметил следующее.Если ваша память нуждается в простых шаблонах (в основном 2-3 типа распределения памяти), вы обычно можете быть лучше, чем распределитель по умолчанию.Вы можете либо предварительно выделить пул буферов при запуске приложения и использовать их по мере необходимости, либо перейти на другой маршрут (выделите огромный массив в начале и предоставьте фрагменты этого при необходимости).По сути, вы пишете свой собственный распределитель памяти.Но скорее всего, вы сделаете хуже, чем распределитель Java по умолчанию.

Я, вероятно, попытался бы сделать следующее: стандартизировать размеры буфера и распределить его нормально.Таким образом, через некоторое время единственное выделение / освобождение памяти будет иметь фиксированные размеры, что значительно поможет быстрому запуску сборщика мусора.Еще одна вещь, которую я хотел бы сделать, - убедиться, что во время разработки алгоритма общая память, необходимая в любой точке, не будет превышать 80-85% памяти машины, чтобы случайно не запустить полную коллекцию.

Помимо этой эвристики, я, вероятно, проверил бы ад любого решения, которое выбрал бы, и посмотрел бы, как оно работает на практике.

...