Как уменьшить сбой одновременного режима Java и чрезмерный сборщик мусора - PullRequest
43 голосов
/ 27 мая 2010

В Java сбой в параллельном режиме означает, что одновременному сборщику не удалось освободить достаточно места в памяти для постоянных и постоянных генераторов, и он должен сдаться и позволить полной 10000 * остановке мира gc Конечный результат может быть очень дорогим.

Я понимаю эту концепцию, но никогда не имел хорошего всестороннего понимания
А) что может вызвать сбой одновременного режима и
Б) в чем решение?

Такая неясность заставляет меня писать / отлаживать код без особых намеков и часто вынуждена искать эти флаги производительности от Foo до Bar без особых причин, просто нужно попробовать.

Я бы хотел узнать у разработчиков, каков ваш опыт? Если вы столкнулись с такой проблемой производительности, какова была причина и как вы ее решили?

Если у вас есть рекомендации по кодированию, не будьте слишком общими. Спасибо!

Ответы [ 4 ]

22 голосов
/ 20 октября 2011

Первое, что я узнал о CMS, это то, что ей нужно больше памяти, чем другим сборщикам, на 25-50% больше - хорошая отправная точка. Это поможет вам избежать фрагментации, поскольку CMS не выполняет никакого уплотнения, как при остановке сборщиками мира. Во-вторых, делайте вещи, которые помогают сборщику мусора; Integer.valueOf вместо нового Integer, избавьтесь от анонимных классов, убедитесь, что внутренние классы не обращаются к недоступным вещам (частным во внешнем классе) и тому подобное. Чем меньше мусора, тем лучше. FindBugs и игнорирование предупреждений очень помогут в этом.

Что касается тюнинга, я обнаружил, что вам нужно попробовать несколько вещей:

-XX: + UseConcMarkSweepGC

Указывает JVM использовать CMS в штатном поколении.

Исправьте размер вашей кучи: -Xmx2048m -Xms2048m Это не позволяет GC выполнять такие вещи, как увеличение и уменьшение кучи.

-XX: + UseParNewGC

использовать параллельное вместо серийного сбора в молодом поколении. Это ускорит ваши второстепенные коллекции, особенно если у вас настроен очень большой молодой генерал. Большое молодое поколение, как правило, хорошо, но не стоит больше половины старого поколения.

-XX: ParallelCMSThreads = X

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

-XX: + CMSParallelRemarkEnabled примечание является последовательным по умолчанию, это может ускорить вас.

-XX: + CMSIncrementalMode позволяет приложению работать больше, проводя GC между фазами

-XX: + CMSIncrementalPacing позволяет JVM рассчитывать изменение частоты сбора данных с течением времени

-XX: CMSIncrementalDutyCycleMin = X Минимальное количество времени, затрачиваемое на GC

-XX: CMSIncrementalDutyCycle = X Начните с выполнения GC в этот% времени

-XX: CMSIncrementalSafetyFactor = X

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

-XX: CMSFullGCsBeforeCompaction = 1

Это очень важно. Он говорит сборщику CMS всегда завершать сбор, прежде чем он начнет новый. Без этого вы можете столкнуться с ситуацией, когда он отбрасывает кучу работы и начинает снова.

-XX: + CMSClassUnloadingEnabled

По умолчанию CMS позволит вашему PermGen расти, пока не убьет ваше приложение через несколько недель. Это останавливает это. Ваш PermGen будет только расти, если вы используете Reflection, или неправильно используете String.intern, или делаете что-то плохое с загрузчиком классов, или несколькими другими вещами.

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

11 голосов
/ 27 мая 2010

Цитируется из "Понимание параллельных записей журналов уборщика мусора"

Ошибка одновременного режима может избегать путем увеличения штатного размер генерации или инициирование CMS сбор при меньшей загруженности кучи установив CMSInitiatingOccupancyFraction до нижнее значение

Однако, если в вашем приложении действительно есть утечка памяти, вы просто выигрываете время.

Если вам нужен быстрый перезапуск и восстановление и вы предпочитаете подход «быстро умереть», я бы предложил вообще не использовать CMS. Я бы придерживался '-XX: + UseParallelGC'.

С "Эргономика сборщика мусора"

Параллельный сборщик мусора (UseParallelGC) бросает исключение нехватки памяти, если чрезмерное количество времени провел сбор небольшого количества куча. Чтобы избежать этого исключения, вы можете увеличить размер кучи. Вы можете также установите параметры -XX:GCTimeLimit=time-limit и -XX:GCHeapFreeLimit=space-limit

3 голосов
/ 27 мая 2010

Иногда ООМ довольно быстр и убит, иногда страдает длительным периодом gc (в прошлый раз было более 10 часов).

Мне кажется, что утечка памяти лежит в основе ваших проблем.

Ошибка CMS не вызовет (насколько я понимаю) OOM. Скорее всего, происходит сбой CMS, потому что JVM необходимо выполнить слишком много сборок слишком быстро, а CMS не может идти в ногу. Одна ситуация, когда за короткий период происходит много циклов сбора, - это когда ваша куча почти заполнена.

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

Вы можете настроить GC так, чтобы он сдавался, когда куча равна 1) в максимальном размере и 2) все еще близка к полному после завершения полного GC. Попробуйте сделать это, если вы еще этого не сделали. Это не излечит ваши проблемы, но, по крайней мере, ваша JVM быстро получит OOM, что позволит быстрее перезапускать и восстанавливать сервис.

РЕДАКТИРОВАТЬ - можно сделать это -XX:GCHeapFreeLimit=nnn, где nnn - это число от 0 до 100, дающее минимальный процент кучи, который должен быть свободен после GC. Значение по умолчанию - 2. Параметр указан на странице с заголовком «Самый полный список параметров -XX для Java 6 JVM» . (Существует множество опций -XX, которые не указаны в документации Sun. К сожалению, на этой странице мало информации о том, что на самом деле делают эти опции.)

Возможно, вам следует начать поиск утечек памяти в вашем приложении / веб-приложении. Если это произойдет, ваши проблемы не исчезнут, если эти утечки не будут найдены и устранены. В долгосрочной перспективе работа с опциями Hotspot GC не устранит утечки памяти.

0 голосов
/ 06 ноября 2011

Я обнаружил, что использование -XX:PretenureSizeThreshold=1m для немедленного перемещения «большого» объекта в постоянное пространство значительно уменьшило количество ошибок моего молодого GC и параллельного режима, поскольку он не пытается сбросить объем данных молодого выжившего + 1 (xmn=1536m survivorratio=3 maxTenuringThreashould=5) до завершения полного цикла CMS. Да, у меня достаточно места для оставшихся в живых, но примерно раз в 2 дня в приложение приходит что-то нужное (и мы запускаем 12 серверов приложений в день для одного приложения).

...