JVM и GC tuning - теория без полного GC

У меня крупномасштабное приложение с двумя типами объектов: длительная жизнь (кеш) и короткая жизнь (запрос-процесс-ответ). Теоретически, с таким типом приложения, я думаю, что можно настроить Young vs Old spaces, поэтому потребление старого пространства является постоянным, в результате чего нет полного GC.

Я изменил параметры newSize-maxNewSize, но, Старая куча продолжает расти до Full GC. После каждого полного GC потребление уменьшается до 20% (кэш занимает 20%). По какой-то причине мои объекты попадают в старое пространство. У меня есть два подозреваемых, почему они переведены в старое пространство:

  • В этой статье: http://chaoticjava.com/posts/gc-tips-and-memory-leaks/ он сказал, что если у вас есть большие объекты, они переходят прямо в Старое пространство. Это правда, и если это так, есть ли параметр параметра JVM Option, который может установить порог размера объекта для пространства Young?

  • Если я правильно понял процесс, объекты переключаются между разделами "От" От выживания "до того, как они перейдут в" Старый раздел ". Есть ли параметр, который может установить, сколько переключателей между To и From должно быть сделано, прежде чем переходить в старое пространство?

Другие советы?

Спасибо, Амар

Ответы

Ответ 1

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

Если вы выделяете большие объекты, можете ли вы использовать пул объектов для них, избегая необходимости их GC. Рассматривали ли вы использование пула объектов для ваших данных запроса/процесса/ответа? например простой - использовать ThreadLocal.

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

Ответ 2

Вы уверены, что рост старого поколения - это просто не кешированные объекты? Если ваш кеш не фиксирован и никогда не меняется, вы будете постоянно добавлять его. Поскольку объекты, которые дошли до старого поколения, истекают из этого кеша, они будут оставаться в памяти до следующего полного GC.

Мне повезло с совпадающим маркером, чтобы полностью исключить длинные паузы из полных GC. Он требует некоторой настройки и может варьироваться в зависимости от приложения. Вот то, что мы используем для запуска 64-битной JVM 24 ГБ с дополнительными секундами GC, при одновременном обслуживании 100 + запросов страниц в секунду с большими кешами:

-Xms24g -Xmx24g -XX:+UseCompressedOops -XX:NewRatio=4 -XX:SurvivorRatio=8    
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+DisableExplicitGC  
-XX:+UseCMSInitiatingOccupancyOnly -XX:+CMSClassUnloadingEnabled  
-XX:+CMSScavengeBeforeRemark -XX:CMSInitiatingOccupancyFraction=68

Ответ 3

Есть ли параметр, который может установить, сколько переключатели между To и From должны быть сделанное до перехода в старое пространство?

Да, -XX:MaxTenuringThreshold

Этот переключатель определяет, сколько раз объекты перепрыгивают между пространствами "От" и "В", до того, как их повысят до старшего поколения. Наибольшее значение - 15 для Java 6 и 31 для более ранних JDK. Значение по умолчанию - 15 для параллельного коллектора и 4 для коллекционеров CMS.

Из документов Sun JVM GC,

Использовать -XX: MaxTenuringThreshold = 0 для перемещения объект, который выживает поколения немедленно поколение.

Как вы хотите сделать противоположное этому, если вы не установили это значение, оно было бы по умолчанию, чего вполне достаточно, чтобы решить, нужно ли входить в Старый объект - при условии, что @Peter говорит: оставшиеся в живых достаточно велики, чтобы удерживать эти объекты.

Что ваш SurvivorRatio установлен? А какая ваша общая куча?

Ответ 4

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

Поскольку мы сохраняем большое количество живых объектов в пространстве оставшихся в живых и продолжаем копировать их из одного места в другое для ряда небольших GC, это увеличивает стоимость младшего GC.

Сохранение большого молодого поколения естественно увеличивает разрыв между последовательными младшими коллекциями и дает больше времени для уничтожения объектов.

Можно провести правильный баланс, поэкспериментируя с этими переменными, чтобы уменьшить продвижение объекта до старого поколения с учетом приемлемых остановок молодого поколения