Коллектор CMS не поспевает за Old Gen

На умеренно загруженном производственном сервере (50 потоков приложений, 30% загрузка ЦП) мы наблюдаем сценарий, когда сборщик CMS не успевает за объектами, продвигаемыми в старое поколение.

Мои первые мысли были о том, что на эти объекты, очевидно, все еще ссылаются, поэтому они не подходят для сбора - но когда Old Gen заполняет и запрашивает серийный сбор, 5,5 ГиБ из 6 ГиБ восстанавливается.

Пространство Eden имеет размер 3 ГиБ и занимает около 20-30 секунд, чтобы заполнить достаточно, чтобы вызвать новую коллекцию. Пространство для выживших колеблется в пределах 800–1250 МБ с максимумом 1,5 ГБ (каждый).

С объектами старого поколения, подходящими для сбора, и сервером, имеющим много (очевидных) ресурсов, я не понимаю, почему сборщик CMS не поддерживает размер старого поколения:

Visual VM

Чем может быть вызван такой сценарий и есть ли решения?

Я знаю о доле занятости, но я не понимаю последствий 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 при запуске

Другие вопросы по тегам