Задний план
У меня есть пакетная программа Spring, которая читает файл (пример файла, с которым я работаю, имеет размер ~ 4 ГБ), выполняет небольшую обработку файла, а затем записывает его в базу данных Oracle.
Моя программа использует 1 поток для чтения файла и 12 рабочих потоков для обработки и отправки базы данных.
Я взбиваю много-много-много памяти молодого поколения, из-за чего моя программа работает медленнее, чем я думаю.
Настраивать
JDK 1.6.18
Весенний пакет 2.1.x
4-ядерный компьютер с оперативной памятью 16 ГБ
-Xmx12G
-Xms12G
-NewRatio=1
-XX:+UseParallelGC
-XX:+UseParallelOldGC
Проблема
С этими параметрами JVM я получаю около 5,x ГБ памяти для Tenured Generation и около 5,X ГБ памяти для Young Generation.
В ходе обработки одного этого файла у моего Tenured Generation все в порядке. Он увеличивается максимум до 3 ГБ, и мне никогда не нужно делать один полный сборщик мусора.
Тем не менее, Молодое поколение много раз достигает своего максимума. Он достигает диапазона 5 ГБ, а затем происходит параллельный второстепенный GC, который очищает Young Gen до 500 МБ. Незначительные сборщики мусора хороши и лучше, чем полный сборщик мусора, но он все равно сильно замедляет мою программу (я почти уверен, что приложение все еще зависает, когда происходит сбор молодого поколения, потому что я вижу, как активность базы данных умирает). Я трачу более 5% своего программного времени на замораживание для незначительных GC, и это кажется чрезмерным. Я бы сказал, за время обработки этого 4-гигабайтного файла я использовал 50–60 ГБ оперативной памяти.
Я не вижу явных недостатков в своей программе. Я пытаюсь следовать общим принципам объектно-ориентированного программирования и писать чистый Java-код. Я стараюсь не создавать объекты без причины. Я использую пулы потоков и, когда это возможно, передаю объекты вместо создания новых объектов. Я собираюсь начать профилирование приложения, но мне интересно, есть ли у кого-нибудь хорошие общие практические правила или анти-шаблоны, чтобы избежать чрезмерного оттока памяти? Является ли 50-60 ГБ памяти для обработки файла размером 4 ГБ лучшим, что я могу сделать? Должен ли я вернуться к трюкам JDk 1.2, таким как объединение объектов? (хотя Брайан Гетц представил презентацию, в которой говорилось, почему объединение объектов глупо, и нам больше не нужно это делать. Я доверяю ему намного больше, чем себе.. :))