Коллектор CMS не поспевает за Old Gen
На умеренно загруженном производственном сервере (50 потоков приложений, 30% загрузка ЦП) мы наблюдаем сценарий, когда сборщик CMS не успевает за объектами, продвигаемыми в старое поколение.
Мои первые мысли были о том, что на эти объекты, очевидно, все еще ссылаются, поэтому они не подходят для сбора - но когда Old Gen заполняет и запрашивает серийный сбор, 5,5 ГиБ из 6 ГиБ восстанавливается.
Пространство Eden имеет размер 3 ГиБ и занимает около 20-30 секунд, чтобы заполнить достаточно, чтобы вызвать новую коллекцию. Пространство для выживших колеблется в пределах 800–1250 МБ с максимумом 1,5 ГБ (каждый).
С объектами старого поколения, подходящими для сбора, и сервером, имеющим много (очевидных) ресурсов, я не понимаю, почему сборщик CMS не поддерживает размер старого поколения:
Чем может быть вызван такой сценарий и есть ли решения?
Я знаю о доле занятости, но я не понимаю последствий CMSIncrementalSafetyFactor
- Я прочитал некоторую документацию по Oracle, но я не знаю, что на самом деле означает "добавление консерватизма при вычислении рабочего цикла"?
альтернативы
Переключение на параллельный / пропускной коллектор приводит к очень низким издержкам GC (1,8%), но оставляет случайные (50 раз в день) длинные паузы - около 20 секунд для каждого полного GC. Даже при некоторой настройке это вряд ли будет соответствовать нашей цели максимальной паузы.
В идеальном мире мы могли бы экспериментировать с коллектором G1, но по разным причинам мы застряли на Java 6 JVM.
1 ответ
Когда вы говорите, что сборщик CMS не поспевает за скоростью продвижения вашего объекта, это означает, что вы должны увидеть "сбои параллельного режима" в журналах GC. Это то, что вы получаете, когда сборщик CMS "проигрывает гонку" и у вас заканчивается память до ее завершения.
2014-02-27T01:09:52.408-0600: 847.004: [GC 847.005: [ParNew
(promotion failed)
Desired survivor size 78512128 bytes, new threshold 2 (max 15)
- age 1: 60284680 bytes, 60284680 total
- age 2: 32342648 bytes, 92627328 total
: 1380096K->1380096K(1380096K), 0.7375510 secs]847.743:
[CMS2014-02-27T01:09:54.133-0600: 848.729: [CMS-concurrent-s
weep: 5.467/6.765 secs] [Times: user=21.59 sys=0.73, real=6.76
secs]
(concurrent mode failure): 2363866K->1763900K(4409856K),
10.6658960 secs] 3697627K->1763900K(5789952K), [CMS Perm :
118666K->117980K(125596K)], 11.4061610 secs]
[Times: user=11.34 sys=0.02, real=11.57 secs]
По умолчанию коллектор CMS сработает на 92% занятости в старом поколении. Судя по темпам роста памяти на графике использования старого поколения, вы увеличиваете примерно 500 МБ каждые 5 минут. 92% от 6 ГБ дают вам около 500 МБ свободного пространства, что означает, что CMS должен выиграть гонку менее чем за 5 минут, что и произойдет. Если...
... что-то происходит за кулисами, кроме гладкого профиля трафика, который мы видим на графике. Например, есть ли у вас какие-либо фоновые процессы, которые обновляют структуры данных в памяти, такие как кеши? Эти виды деятельности создают внезапное огромное количество новых, долгоживущих объектов, которые необходимо продвигать к старому поколению. Это внезапно сделает ваш плавный график вертикальным и может быстро исчерпать доступную память. Коллектор CMS хорошо справляется с плавным, устойчивым трафиком, но он очень уязвим для быстрых всплесков активности. Он хорошо реагирует на постепенные изменения в скорости генерации мусора, но не может предвосхитить "бурное" поведение, и я видел много подобных случаев, которые приводят к тому, что он проигрывает гонку.
Помимо полного избежания фоновых процессов, которые производят внезапные всплески новых объектов, вы можете дать коллектору CMS преимущество, уменьшив параметр CMSInitiatingOccupancyFraction до 60–80, а не по умолчанию 92%.
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
Кроме того, следите за своим пространством PermGen тоже. В отличие от сборщика параллельной пропускной способности, сборщик CMS не собирает PermGen по умолчанию, поэтому, если он когда-либо будет заполнен, вы получите полный сборщик мусора "останови мир". Этот параметр заставляет сборщик CMS собирать пространство PermGen: CMSClassUnloadingEnabled.
Кроме этого, я рекомендую включить ведение журнала и настройку GC: -XX:+PrintGCDetails печатает сведения о каждой незначительной и основной сборке мусора
Это отличный параметр, который позволяет видеть каждый параметр JVM при запуске: -XX:+PrintFlagsFinal печатает значение всех параметров конфигурации JVM при запуске