Сборка мусора Java G1 в производстве

Поскольку Java 7 по умолчанию будет использовать новую сборку мусора G1, сможет ли Java обрабатывать большую кучу на порядок, не предполагая "разрушительного" времени паузы GC? Кто-нибудь на самом деле внедрил G1 в производство, каков был ваш опыт?

Чтобы быть справедливым, единственный раз, когда я видел действительно длинные паузы GC, на очень больших кучах, гораздо больше, чем рабочая станция. Уточнить мой вопрос; откроет ли G1 шлюз в сотни ГБ? ТБ?

16 ответов

Решение

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

Сборка мусора - это не просто сделка "Эй, она полная, давайте переместим все сразу и начнем все сначала" - это фантастически сложная многоуровневая фоновая система. Он может выполнять большую часть своего обслуживания в фоновом режиме без каких-либо пауз, а также использует знание ожидаемых шаблонов системы во время выполнения, чтобы помочь - например, предположить, что большинство объектов умирает сразу после создания, и т. Д.

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

РЕДАКТИРОВАТЬ:

при повторном чтении мне пришло в голову, что я использую Java ежедневно -Eclipse, Azureus и приложения, которые я разрабатываю, и это было ДОЛГОЕ ВРЕМЯ, так как я увидел паузу. Не существенная пауза, но я имею в виду любую паузу вообще.

Я видел паузы, когда я щелкаю правой кнопкой мыши на проводнике Windows или (иногда), когда я подключаю определенное оборудование USB, но с Java- нет вообще.

GC все еще проблема с кем-либо?

Я тестировал его с тяжелым приложением: 60-70 ГБ выделено для кучи, а 20-50 ГБ используется в любое время. С такими приложениями не стоит говорить, что ваш пробег может отличаться. Я использую JDK 1.6_22 в Linux. Незначительные версии важны - примерно до 1.6_20 в G1 были ошибки, которые вызывали случайные исключения NullPointerException.

Я обнаружил, что он очень хорошо держит цель паузы, которую вы даете ей большую часть времени. По умолчанию используется пауза в 100 мс (0,1 секунды), и я сказал ей сделать это вдвое меньше (-XX:MaxGCPauseMillis=50). Тем не менее, как только у него становится мало памяти, он паникует и выполняет полную сборку мусора с остановками. С 65 ГБ это занимает от 30 секунд до 2 минут. (Количество процессоров, вероятно, не имеет значения; возможно, оно ограничено скоростью шины.)

По сравнению с CMS (которая не является GC-сервером по умолчанию, но должна использоваться для веб-серверов и других приложений реального времени), типичные паузы гораздо более предсказуемы и их можно сделать намного короче. До сих пор мне больше повезло с CMS для огромных пауз, но это может быть случайным; Я вижу их только несколько раз каждые 24 часа. Я не уверен, какой из них будет более подходящим в моей производственной среде на данный момент, но, вероятно, G1. Если Oracle продолжит настраивать его, я подозреваю, что в конечном итоге победит G1.

Если у вас нет проблем с существующими сборщиками мусора, нет оснований рассматривать G1 прямо сейчас. Если вы используете приложение с малой задержкой, такое как приложение с графическим интерфейсом, G1, вероятно, является правильным выбором, с MaxGCPauseMillis, установленным на действительно низкое значение. Если вы используете приложение в пакетном режиме, G1 ничего вам не купит.

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

Мы используем следующие настройки JVM:

-server -Xms512m -Xmx3076m -XX:NewRatio=50 -XX:+HeapDumpOnOutOfMemoryError -XX:+UseG1GC -XX:+AggressiveOpts -XX:+UnlockExperimentalVMOptions -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000 -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime

обновленный

-d64 -server -Xss4m -Xms1024m -Xmx4096m -XX:NewRatio=50 -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+HeapDumpOnOutOfMemoryError -XX:-DisableExplicitGC -XX:+AggressiveOpts -Xnoclassgc -XX:+UseNUMA -XX:+UseFastAccessorMethods -XX:ReservedCodeCacheSize=48m -XX:+UseStringCache -XX:+UseStringDeduplication -XX:MaxGCPauseMillis=400 -XX:GCPauseIntervalMillis=8000

Хотя я не тестировал G1 в производстве, я подумал, что прокомментирую, что GC уже проблематичны для случаев без "огромных" куч. В частности, GC может серьезно повлиять на услуги, скажем, на 2 или 4 гигабайта. ГХ молодого поколения обычно не представляют проблем, поскольку они заканчиваются за однозначные миллисекунды (или не более двухзначных). Но коллекции старого поколения гораздо более проблематичны, так как они занимают несколько секунд с размерами старого поколения от 1 гига и выше.

Теперь: в теории CMS может сильно помочь, поскольку он может выполнять большую часть своей работы одновременно. Однако со временем будут случаи, когда он не сможет этого сделать и вынужден будет прибегнуть к помощи коллекции "Остановить мир". И когда это произойдет (скажем, через 1 час - не часто, но все же слишком часто), хорошо, держитесь за свои чертовы шляпы. Это может занять минуту или больше. Это особенно проблематично для служб, которые пытаются ограничить максимальную задержку; вместо обработки запроса, скажем, 25 миллисекунд, теперь требуется десять секунд или более. Чтобы добавить травму к оскорблению, клиенты будут часто тайм-аут запроса и повторять, что приводит к дальнейшим проблемам (так называемый "шторм с дерьмом").

Это одна из областей, где G1 надеется помочь. Я работал в большой компании, которая предлагает облачные сервисы для хранения и отправки сообщений; и мы не могли использовать CMS, потому что большую часть времени она работала лучше, чем параллельные сорта, у нее были эти расплавления. Так около часа все было хорошо; и затем что-то попало в вентилятор... и потому что сервис был основан на кластерах, когда один узел попадал в беду, другие обычно следовали (поскольку тайм-ауты, вызванные GC, приводят к тому, что другие узлы полагают, что узел вышел из строя, что привело к перенаправлению).

Я не думаю, что GC представляет собой большую проблему для приложений, и, возможно, реже затрагиваются даже некластеризованные сервисы. Но все больше и больше систем кластеризуются (особенно благодаря хранилищам данных NoSQL), и размеры кучи растут. GC OldGen суперлинейно связаны с размером кучи (это означает, что удвоение размера кучи более чем удваивает время GC, при условии, что размер действующего набора данных также удваивается).

Технический директор Azul, Гил Тене (Gil Tene), имеет хороший обзор проблем, связанных с сборкой мусора, а также обзор различных решений в своей презентации " Понимание Java-сборки мусора" и "Что вы можете с этим сделать", и в этой статье есть дополнительные подробности: http://www.infoq.com/articles/azul_gc_in_detail.

Сборщик мусора C4 Azul в нашей виртуальной машине Zing является параллельным и параллельным, и использует один и тот же механизм GC для нового и старого поколений, работая одновременно и уплотняя в обоих случаях. Что наиболее важно, у C4 нет никакого отступления остановки мира. Все уплотнения выполняются одновременно с запущенным приложением. У нас есть клиенты, работающие очень большими (сотни ГБайт) с худшим временем задержки GC <10 мсек, а в зависимости от приложения часто менее 1-2 мсек.

Проблема с CMS и G1 состоит в том, что в какой-то момент память кучи Java должна быть сжата, и оба этих сборщика мусора останавливают мир /STW (то есть приостанавливают приложение) для выполнения сжатия. Таким образом, хотя CMS и G1 могут выдвигать паузы STW, они не устраняют их. Однако C4 от Azul полностью исключает паузы STW, и поэтому у Zing такие низкие паузы GC даже для гигантских размеров кучи.

И чтобы исправить утверждение, сделанное в предыдущем ответе, Zing не требует каких-либо изменений в операционной системе. Он работает так же, как и любая другая JVM в неизмененных дистрибутивах Linux.

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

Недавно я был перемещен из

CMS в G1GC с кучей 4G и 8-ядерным процессором на серверах с JDK 1.7.45.

(JDK 1.8.x G1GC предпочтительнее, чем 1.7, но из-за некоторых ограничений я должен придерживаться версии 1.7.45)

Я настроил ниже основные параметры и оставил все остальные параметры в значения по умолчанию.

-XX:G1HeapRegionSize=n, XX:MaxGCPauseMillis=m, -XX:ParallelGCThreads=n, 
-XX:ConcGCThreads=n apart from -Xms and -Xmx

Если вы хотите точно настроить эти параметры, взгляните на эту статью оракула.

Основные наблюдения:

  1. Использование памяти согласуется с G1GC в отличие от максимумов и минимумов с CMS
  2. Максимальное время паузы GC меньше по сравнению с CMS
  3. Время, затрачиваемое на сборку мусора, немного больше в G1GC по сравнению с CMS.
  4. Количество основных коллекций практически ничтожно мало по сравнению с CMS
  5. Количество второстепенных коллекций выше по сравнению с CMS

Но все же я рад, что время паузы Max GC меньше, чем у CMS. Я установил максимальное время паузы GC как 1,5 секунды, и это значение еще не пересечено.

Связанный вопрос SE:

Java 7 (JDK 7) сборка мусора и документация по G1

Кажется, что G1, запускающий JDK7u4, наконец-то официально поддерживается, см. RN для JDK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html.

Наше тестирование еще для больших JVM настроенных CMS по-прежнему действует лучше, чем G1, но я думаю, что он будет расти лучше.

Я только что внедрил G1 Garbage Collector в нашем проекте Terracotta Big Memory. Работая над разными типами коллекторов, G1 дал нам лучшие результаты с временем отклика менее 600 мс.

Вы можете найти результаты теста (всего 26) здесь

Надеюсь, поможет.

CMS может привести к медленному снижению производительности, даже если вы работаете с ней без накопления постоянных объектов. Это из-за фрагментации памяти, которой G1 якобы избегает.

Миф о G1, доступном только с платной поддержкой, - это всего лишь миф. Sun и Oracle уже разъяснили это на странице JDK.

G1 GC должен работать лучше. Но если установить -XX:MaxGCPauseMillis слишком агрессивно, мусор будет собираться слишком медленно. И вот почему полный GC сработал на примере Дэвида Леппика.

Я недавно перенес часть Twicsy на новый сервер с 128 ГБ ОЗУ и решил использовать 1.7. Я начал использовать все те же настройки памяти, что и в 1.6 (у меня есть несколько экземпляров, выполняющих различные операции, от 500 МБ кучи до 15 ГБ, а теперь и новой с 40 ГБ), и это не сработало совсем, 1.7, похоже, использует больше кучи, чем 1.6, и за первые несколько дней у меня возникло много проблем. К счастью, у меня было достаточно оперативной памяти, и я увеличил объем оперативной памяти для большинства моих процессов, но все еще имел некоторые проблемы. Моим обычным МО было использовать очень маленький минимальный размер кучи 16 м, даже с максимальной кучей в несколько гигабайт, а затем включить инкрементальный сборщик мусора. Это сводило паузы к минимуму. Это сейчас не работает, и мне пришлось увеличить минимальный размер примерно до того, что я ожидал использовать в среднем в куче, и это сработало очень хорошо. У меня все еще включен инкрементальный сборщик мусора, но я буду пробовать без него. Теперь никаких пауз, и кажется, что все идет очень быстро. Итак, я думаю, что мораль этой истории заключается в том, что не стоит ожидать, что ваши настройки памяти будут идеально переведены с 1,6 на 1,7.

G1 делает приложение намного более гибким: широта приложения возрастет - приложение можно назвать "мягким в реальном времени". Это делается путем замены двух видов прогонов GC (маленьких второстепенных и одного большого на Tenured Gen) равными маленьким.

Для более подробной информации посмотрите на это: http://geekroom.de/java/java-expertise-g1-fur-java-7/

Я использую G1GC на Java 8, а также с Groovy (также Java 8), и я выполняю различные виды рабочих нагрузок, и в целом G1GC работает так:

  • Использование памяти очень низкое, например, 100 МБ вместо 500 МБ по сравнению с настройками Java по умолчанию

  • Время отклика является постоянным и очень низким

  • Производительность между настройками по умолчанию и G1GC составляет 20% замедления при использовании G1GC в худшем случае (без настройки, однопоточное приложение). Это не так много, учитывая хорошее время отклика и низкое использование памяти.

  • При работе с многопоточным Tomcat общая производительность на 30% выше, а использование памяти намного ниже, а время отклика значительно ниже.

Таким образом, в целом, при использовании действительно различных рабочих нагрузок G1GC является очень хорошим сборщиком для Java 8 для многопоточных приложений, и даже для однопоточных приложений есть некоторые преимущества.

Я работаю с Java, для маленькой и большой кучи, и вопрос о GC и Full GC появляется каждый день, так как ограничения могут быть более строгими, чем другие: в определенных условиях, 0,1 секунды GC или Full GC мусорщика, kill важна просто функция fonctionnalité, а также ее мелкозернистая конфигурация и возможности (CMS, iCMS, другие... цель заключается в том, чтобы получить максимально возможное время отклика при обработке почти в реальном времени (здесь обработка в реальном времени часто составляет 25 мс) Итак, в принципе, любые улучшения в эргономике GC и heuristique приветствуются!

Не рекомендуется использовать java8 с G1GC для вычисления чисел с плавающей точкой с помощью JVM, подобной горячей точке. Это опасно для целостности и точности приложения.

https://bugs.openjdk.java.net/browse/JDK-8148175

JDK-8165766

JDK-8186112

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