Настройка JVM (GC) для высокопроизводительного серверного приложения - PullRequest
8 голосов
/ 30 апреля 2010

Я использую сервер приложений на 64-битной ОС Linux с 8-ядерными процессорами и 6 ГБ памяти.

Сервер должен быть очень отзывчивым.

После некоторой проверки я обнаружил, что приложение, работающее на сервере, создает довольно большое количество недолговечных объектов и имеет только около 200 ~ 400 МБ долгоживущих объектов (до тех пор, пока нет утечки памяти) *

После прочтения http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html Я использую эти опции JVM

-server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC

Результат: второстепенный сборщик занимает 0,01 ~ 0,02 с, основной сборщик занимает 1 ~ 3 с второстепенный сбор происходит постоянно.

Как я могу улучшить или настроить JVM?

больший размер кучи? но займет ли это больше времени для GC?

больше NewSize и MaxNewSize (для молодого поколения)?

другой коллекционер? параллельный GC?

Это хорошая идея, чтобы крупные GC проходили чаще? и как?

Ответы [ 7 ]

8 голосов
/ 30 апреля 2010

Результат: второстепенный ГК занимает 0,01 ~ 0,02 с, основной ГК занимает 1 ~ 3 с, минорный ГК происходит постоянно.

Если вы не сообщаете о паузах, я бы сказал, что сборщик CMS делает то, о чем вы его просили. По определению, CMS будет использовать больший процент ЦП, чем последовательный и параллельный коллекторы. Это штраф, который вы платите за малое время паузы.

Если вы видите от 1 до 3 секунд паузы раз, я бы сказал, что вам нужно выполнить некоторые настройки. Я не эксперт, но, похоже, вам следует начать с уменьшения значения CMSInitiatingOccupancyFraction со значения по умолчанию 92.

Увеличение размера кучи улучшит «пропускную способность» ГХ. Но если ваша проблема - длинные паузы, увеличение размера кучи может усугубить проблему.

3 голосов
/ 22 марта 2012

Осторожно .... GC может быть волосатым предметом, если вы не будете осторожны. В любой среде выполнения (JVM для Java / CLR для .Net) происходит несколько процессов. Как правило, существует ранняя стадия оптимизации памяти (Сборка мусора молодого поколения / Сборщик мусора молодого поколения и Сборка мусора старого поколения / Сборщик мусора старого поколения). Молодой ген gc происходит регулярно и обычно приписывается вашим меньшим паузам / сбоям. Старый gen gc - это обычно то, что происходит, когда вы видите длинные паузы "останови мир".

Почему вы можете спросить? Причина, по которой вы получаете паузы с вашей средой выполнения / JVM, заключается в том, что когда среда выполнения очищает от кучи, она должна пройти через то, что называется изменением фазы. Он останавливает потоки, выполняющие ваше приложение, чтобы помечать и менять местами указатели для оптимизации доступной памяти. Yong gen быстрее, поскольку он в основном выпускает объекты, которые являются только временными. Однако, старый ген оценивает все объекты в куче, и когда у вас закончится память, он пойдет, чтобы освободить столь необходимую память.

Почему осторожно? Старый ген экспоненциально ухудшается во время паузы, чем больше кучи вы используете. при общем объеме кучи 2-4 ГБ у вас все будет хорошо в современных средах выполнения, таких как Java 6 (JDK 1.6+). Когда вы выйдете за пределы этого предела, вы увидите экспоненциальное увеличение времени паузы. Я столкнулся с некоторыми клиентами, которым приходится перезапускать серверы - как в некоторых редких случаях, когда куча велика, время приостановки GC может занять больше времени, чем полный перезапуск.

Есть несколько новых инструментов, которые довольно круты и могут дать вам преимущество в оценке, если GC - ваша боль. JHiccup - один из них, и он бесплатный с сайта azulsystems . В настоящее время я думаю, что это только для Linux. У них также есть JVM с восстановленным алгоритмом GC, который работает без пауз ... но если вы используете развертывание на одном сервере с некритическим приложением, это может быть экономически не выгодно (это не бесплатно).

Подводя итог - если ваша куча времени выполнения / JVM / CLR меньше 2 ГБ, добавление дополнительной памяти поможет. Не забудьте дать себе немного накладных расходов. Вы никогда не захотите достичь 100% размера кучи / объема памяти, если это возможно. Это когда длинные паузы самые длинные. Дайте себе дополнительно 20% + памяти сверх того, что, по вашему мнению, вам понадобится. Таким образом, у алгоритмов GC есть место для перемещения объектов для оптимизации. Если вы когда-нибудь планируете стать крупным ... есть один инструмент, который исправляет технологию JVM примерно 1990 года (Azul Systems Zing JVM), но она не бесплатна. Они предлагают инструмент с открытым исходным кодом для диагностики проблем GC. В JVM (как я уже пробовал) также есть действительно классный инструмент видимости на уровне потоков, который позволяет вам сообщать о любых утечках, ошибках или блокировках в работе без дополнительных затрат (некоторый прием с выгрузкой данных, с которыми JVM уже имеет дело, и отметками времени). Это сэкономило тонны времени тестирования разработчиков ... но опять же, не для небольших приложений.

Оставайтесь ниже 4 ГБ. Дайте дополнительный запас. И если вы хотите, вы можете включить эти флаги для мониторинга GC для Java / JVM:

java -verbose:gc myProgram
java -Xloggc:D:/log/myLogFile.log -XX:+PrintGCDetails myProgram

Вы можете попробовать другие коллекторы, которые использует Hotspot. Их больше одного.

Если вы работаете в Linux, попробуйте и инструмент JHiccup. Это бесплатно.

2 голосов
/ 30 апреля 2010

Возможно, вам будет интересно попробовать сборщик мусора-первого с низкой паузой вместо одновременной очистки разметки (хотя он не обязательно более производительный для всех сборок, он должен иметь лучший худший случай). Он включен -XX:+UseG1GC и должен быть действительно потрясающим соусом, но вы, возможно, захотите дать ему тщательную оценку, прежде чем использовать его в производстве. С тех пор, вероятно, он улучшился, но год назад он, похоже, был немного ошибочным, как видно из Опыт работы с JDK 1.6.x G1 («Garbage First»)

1 голос
/ 17 октября 2012

Для серверных приложений с высокой скоростью отклика, я думаю, вы хотите, чтобы основной GC происходил реже. Вот список параметров поможет.

-XX: + CMSParallelRemarkEnabled
-XX: + CMSScavengeBeforeRemark
-XX: + UseCMSInitiatingOccupancyOnly
-XX: CMSInitiatingOccupancyFraction = 50
-XX: CMSWaitDuration = 300000
-XX: GCTimeRatio = 40

Больший размер кучи может не помочь при низкой паузе, если вашему приложению не хватает памяти.

Увеличение пропускной способности NewSize и MaxNewSize может помочь при пропускной способности, но может не помочь при низкой паузе. Если вы решите использовать этот подход, вы можете рассмотреть возможность увеличения потоков выполнения GC, установив -XX: GCTimeRatio ниже. Суть в том, чтобы не забывать о целостности при настройке JVM.

1 голос
/ 25 апреля 2011

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

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

1 голос
/ 30 апреля 2010

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

То, что вы хотите, - это быть абсолютно уверенным, что вы не столкнетесь со сценарием, в котором сборщик мусора приостанавливает вашу основную программу.

Вы пытались просто не указывать никаких флагов, кроме как сказать, что хотите использовать виртуальную машину сервера (для Sun JVM), а затем подвергнуть свой сервер большой нагрузке, чтобы посмотреть, как он себя ведет? Только тогда вы сможете увидеть, если вы получите какие-либо улучшения от работы с опциями.

0 голосов
/ 17 июля 2013

Я думаю, что предыдущие плакаты упустили что-то очень очевидное - размер Пермской генерации слишком мал. Если система использует от 200 до 400 МБ в качестве постоянной генерации, то лучше всего установить Max Perm Gen на 400 МБ. размер PerGen также должен быть установлен на то же значение. Тогда вы никогда не исчерпаете пространство постоянного поколения.

В настоящее время - похоже, что JVM должна тратить много времени на перемещение объектов в постоянное поколение и из него. Это может занять время. JVM пытается выделить смежные области памяти для объектов Java - это ускоряет доступ к памяти благодаря функциям аппаратного уровня. Для этого очень полезно иметь много буфера в памяти. Если Permanent Generation почти заполнен, вновь обнаруженные постоянные объекты должны быть разделены или существующие объекты должны быть перемешаны. Это то, что запускает полный GC, а также вызывает длинные полные паузы GC.

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

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

Люди считают варианты GC решениями, не оценивая, насколько зрелыми они оказались в фактическом использовании.

...