(Получилось несколько долго; в конце есть реальное предложение по исправлению.)
Очень очень кратко, сборка мусора при использовании -XX: + UseConcMarkSweepGC работает так:
Все объекты выделены в так называемое молодое поколение. Обычно это от пары сотен мегабайт до гигабайта, в зависимости от настроек виртуальной машины, количества процессоров и общего размера кучи. Молодое поколение собирается в паузу "останови мир", за которой следует параллельная (многоядерная) сборка компактных (движущихся объектов). Молодое поколение рассчитано на то, чтобы сделать эту паузу достаточно большой.
Когда объекты выжили (все еще достижимы) молодого поколения, они получают повышение до "старого поколения" (старое поколение).
В старом поколении запускается -XX: + UseConcMarkSweepGC. В режиме по умолчанию (без -XX: + UseConcMarkSweepGC), когда старое поколение заполняется, вся куча собирается и сжимается (перемещается, устраняя фрагментацию) сразу в стоп-мире. Эта пауза обычно дольше, чем паузы молодого поколения, потому что задействована куча вся , которая больше.
В CMS (-XX: + UseConcMarkSweepGC) работа по сжатию старого поколения в основном выполняется одновременно (имеется в виду, что работа в фоновом режиме с приложением не приостановлена). Эта работа также не компактирование; он работает больше как malloc () / free () и вы подвержены фрагментации.
Основным преимуществом CMS является то, что, когда все работает хорошо, вы избегаете длинных периодов паузы, которые линейны по размеру кучи, потому что основная работа выполняется одновременно (есть некоторые шаги остановки мира, но они обычно должны быть короткими).
Два основных недостатка:
- Вы подвержены фрагментации, поскольку old-gen не уплотнен.
- Если вы не завершите параллельный цикл сбора до заполнения старого поколения или если фрагментация предотвращает выделение, итоговая полная коллекция всей кучи будет не параллельной, как это происходит со сборщиком по умолчанию , То есть используется только один процессор. Это означает, что когда / если вы do попадете на полную сборку мусора, пауза будет на длиннее , чем это было бы со сборщиком по умолчанию.
Теперь ... ваши логи. «Сбой одновременного режима» предназначен для того, чтобы передать, что параллельная работа по метке / развертке не была завершена вовремя для другого GC молодого поколения, которому необходимо продвигать выжившие объекты в старое поколение. «Сбой при продвижении» заключается скорее в том, что при переходе от молодого поколения к старому не удалось выделить объект в старом поколении из-за фрагментации.
Если вы не столкнулись с настоящей ошибкой в JVM, внезапное увеличение использования кучи почти наверняка связано с вашим приложением, JBoss или каким-либо внешним объектом, действующим в вашем приложении. Так что я не могу помочь с этим. Однако то, что, вероятно, происходит, является комбинацией двух вещей:
- Пик активности вызывает слишком быстрое увеличение использования кучи для одновременного завершения одновременного сбора.
- Old-gen слишком фрагментирован, что вызывает проблемы, особенно когда old-gen почти заполнен.
Я должен также отметить, что поведение CMS по умолчанию состоит в том, чтобы пытаться отложить одновременные коллекции как можно дольше (но не слишком long) по соображениям производительности. Чем позже это происходит, тем эффективнее (с точки зрения использования процессора) коллекция. Однако компромисс заключается в том, что вы увеличиваете риск того, что вы не закончите вовремя (что опять-таки вызовет полный GC и долгую паузу). Это также должно (я не проводил здесь эмпирических тестов, но это понятно) должно привести к тому, что фрагментация будет вызывать большую озабоченность; в основном, чем полнее старое поколение, когда продвигается объект, тем больше вероятность того, что продвижение объекта ухудшит проблемы фрагментации (слишком долго, чтобы вдаваться в детали).
В вашем случае я бы сделал две вещи:
- Продолжайте выяснять, что вызывает активность. Я бы сказал, что маловероятно, что это ошибка GC / JVM.
- Переконфигурируйте JVM для запуска параллельных циклов сбора данных раньше, чтобы избежать переполнения кучи так, что фрагментация становится особенно серьезной проблемой, и дает ей больше времени для завершения во времени даже во время ваших внезапных всплесков активности.
Вы можете достичь (2) легче всего, используя опции JVM
-XX:CMSInitiatingOccupancyFraction=75
-XX:+UseCMSInitiatingOccupancyOnly
, чтобы явно заставить JVM запустить цикл CMS с определенным уровнем использования кучи (в этом примере 75% - вам может понадобиться это изменить; чем ниже процент, тем раньше он будет срабатывать).
Обратите внимание, что в зависимости от того, какой у вас размер живого файла (количество действительных и достижимых байтов) в вашем приложении, для форсирования более раннего цикла CMS может также потребоваться увеличить размер кучи, чтобы избежать постоянной работы CMS (не хорошее использование процессора).