#java #garbage-collection #jvm #performance
#java #сборка мусора #jvm #Производительность
Вопрос:
У меня есть крупномасштабное приложение с двумя типами объектов: с длительным сроком службы (кэш) и коротким сроком службы (запрос-процесс-ответ). Теоретически, я думаю, что в приложениях такого типа можно настроить «Молодые» и «Старые» пространства, чтобы потребление старого пространства было постоянным, что не приводило к полному GC.
Я изменил параметры NewSize-MaxNewSize, но старая куча продолжает расти до полного GC. После каждого полного GC потребление снижается до 20% (кэш занимает 20%). По какой-то причине мои объекты попадают в старое пространство. У меня есть два подозреваемых, почему они перемещены в старое пространство:
-
Согласно этой статье: http://chaoticjava.com/posts/gc-tips-and-memory-leaks сказано, что если у вас выделены большие объекты, они отправляются непосредственно в старое пространство. Верно ли это, и если да, то существует ли параметр параметра JVM, который может устанавливать пороговый размер объекта для Young space?
-
Если я правильно понял процесс, объекты переключаются между разделами выживания «Туда-из», прежде чем перемещаться в старый раздел. Есть ли параметр, который может установить, сколько переключений между To и From необходимо выполнить перед переходом в старое пространство?
Есть еще советы?
Спасибо, Амар
Ответ №1:
Похоже, что ваши пробелы для выживания недостаточно велики. Вам нужно сделать их достаточно большими, чтобы не требовалось собирать объекты. Объект переключается в пространство выживания и выходит из него только один раз.
Если вы выделяете большие объекты, можете ли вы использовать для них пул объектов, избегая необходимости их сбора. Рассматривали ли вы возможность использования пула объектов также для данных вашего запроса / процесса / ответа? например, простой вариант — использовать ThreadLocal.
Вы пробовали G1 collector, который предназначен для постепенного сбора всей вашей памяти и уменьшения большого воздействия полного GC.
Ответ №2:
Вы уверены, что рост старого поколения — это просто не кэшированные объекты? Если ваш кэш не исправлен и никогда не меняется, вы будете постоянно добавлять к нему. Поскольку срок действия объектов, которые попали в старое поколение, истекает из этого кэша, они останутся в памяти до следующего полного GC.
Мне гораздо больше повезло с сборщиком параллельной развертки mark, чтобы полностью исключить длительные паузы в полной GCS. Требуется небольшая настройка, и она может варьироваться в зависимости от приложения. Вот что мы используем для запуска 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
Комментарии:
1. WhiteFang34 Нужно ли мне удалить эти параметры: -Dsun.rmi.dgc.client.gcInterval = 3600000 и -Dsun.rmi.dgc.server.gcInterval = 3600000 из моих параметров JVM, если я хочу попробовать ваши параметры?
2. @Yoldar-Zi вы можете сохранить эти параметры RMI.
Ответ №3:
Есть ли параметр, который может установить, сколько переключений между To и From необходимо выполнить перед переходом в старое пространство?
ДА, -XX:MaxTenuringThreshold
Этот переключатель определяет, сколько раз объекты перемещаются между пространствами «From» и «To», оставшимися в живых, прежде чем перейти к старшему поколению. Наибольшее значение равно 15 для Java 6 и 31 для более ранних JDK. Значение по умолчанию равно 15 для параллельного сборщика и равно 4 для сборщиков CMS.
Из документации Sun JVM GC,
Используйте -XX:MaxTenuringThreshold=0, чтобы немедленно переместить объект, который сохраняется в коллекции молодого поколения, в постоянное поколение.
Поскольку вы хотите сделать обратное, если вы не установили это значение, оно будет по умолчанию, чего вполне достаточно, чтобы решить, нужно ли объекту переходить в Old — при условии, что @Peter говорит, что оставшиеся в живых достаточно велики, чтобы вместить эти объекты.
Каков ваш параметр SurvivorRatio? И какова ваша общая куча?
Ответ №4:
Критическую роль здесь играют характеристики времени жизни объекта.Важными регуляторами настройки являются размер оставшегося пространства, порог срока службы и размер молодого поколения. Стратегически мы хотим, чтобы объекты умирали молодыми, поэтому, если существует достаточный разрыв между второстепенными коллекциями, многие объекты погибнут в молодом поколении. Кроме того, мы можем настроить порог сохранения, чтобы объекты оставались в пространстве выживания для желаемого количества коллекций.
Поскольку мы храним большое количество живых объектов в пространстве survivor и продолжаем копировать их из одного пространства в другое для нескольких второстепенных GC, это увеличивает стоимость второстепенного GC.
Сохранение большого молодого поколения, естественно, увеличивает разрыв между последовательными второстепенными коллекциями и дает больше времени объектам для смерти.
Можно найти правильный баланс, поэкспериментировав с этими переменными, чтобы сократить продвижение объектов до старого поколения с учетом приемлемых пауз для молодого поколения