Как бороться с длинным циклом полного сбора мусора в Java - PullRequest
2 голосов
/ 01 мая 2019

Мы унаследовали систему, которая работает в производственном процессе и в последнее время начала выходить из строя каждые 10 часов.По сути, наше внутреннее программное обеспечение помечает систему, которая вышла из строя, если она не отвечает в течение минуты.Мы обнаружили, что наша проблема в том, что наши полные циклы GC длятся 1,5 минуты, мы используем кучу 30 ГБ.Теперь проблема в том, что мы не можем много оптимизировать за короткий промежуток времени и не можем быстро разделить наш сервис, но нам нужно как можно быстрее избавиться от пауз в 1,5 минуты, так как наша система выходит из строя из-за этих пауз в работе.Для нас допустимая задержка составляет 20 миллисекунд, но не более.Что будет самым быстрым способом настройки системы?Уменьшить кучу, чтобы часто запускать GC?Использовать подсказки System.gc ()?Любые другие решения?Мы используем настройки по умолчанию в Java 8, и у нас появляется все больше и больше пользователей - то есть создается все больше и больше объектов.

Некоторые данные GC

enter image description here

Ответы [ 3 ]

2 голосов
/ 01 мая 2019

Не существует универсального решения для вашей проблемы: вам нужно хорошо разбираться в шаблонах распределения и жизнеспособности вашего приложения, и вам нужно знать, как это взаимодействует с конкретными алгоритм сбора мусора, который вы используете (функция версии Java и флаги командной строки передаются в java).

Вообще говоря, Full GC (который успешно восстанавливает много места) означает, что множество объектов переживает второстепенные коллекции (но не протекает). Начните с рассмотрения размера ваших пространств Eden и Survivor: если Eden слишком мал, второстепенные коллекции будут выполняться очень часто, и, возможно, вы не дадите объекту умереть до того, как будет достигнут порог владения. Если Выжившие слишком малы, объекты будут преждевременно повышены до Старого поколения.

Настройка ГХ - это немного искусства: вы запускаете свое приложение, изучаете результаты, настраиваете некоторые параметры и запускаете его снова. Таким образом, вам потребуется эталонная версия вашего приложения, которая ведет себя как можно ближе к рабочей, но, надеюсь, не потребует 10 часов для создания полного GC.

Поскольку вы заявили, что используете Java 8 с настройками по умолчанию, я считаю, что это означает, что ваши старые коллекции работают с последовательным сборщиком. Вы можете увидеть некоторые очень быстрые улучшения, переключившись на параллельный коллектор для старого поколения (-XX: + UseParallelOldGC). Хотя это может уменьшить паузу в 1,5 минуты до некоторого количества секунд (в зависимости от количества ядер в вашем ящике и количества потоков, указанных для GC), это не уменьшит максимальную паузу до 20 мс.

2 голосов
/ 01 мая 2019

У вас много сохраненных данных. Есть несколько вариантов, которые стоит рассмотреть.

  • увеличьте кучу до 32 ГБ, это мало повлияет, если у вас есть свободная память. Если снова взглянуть на ваши итоговые данные, вы увидите, что вы используете 32 ГБ, а не 30 ГБ, поэтому это может не помочь.
  • если у вас недостаточно свободной памяти, возможно, что небольшая часть вашей кучи переставляется, поскольку это может значительно увеличить время полного GC.
  • Возможно, есть несколько простых способов сделать структуры данных более компактными. например используйте компактные строки, используйте примитивы вместо оберток, например long для отметки времени вместо Date или LocalDateTime. (long составляет около 1/8 размера)
  • Если ни один из этих способов не помог, попробуйте переместить некоторые данные из кучи. например Chronicle Map - это ConcurrentMap, в котором используется память без кучи, что может значительно сократить время GC т. е. нет никаких издержек GC для данных, хранящихся вне кучи. Насколько легко это добавить, зависит от того, как структурированы ваши данные.

Я предлагаю проанализировать, как структурированы ваши данные, чтобы увидеть, есть ли какие-нибудь простые способы сделать их более эффективными.

0 голосов
/ 01 мая 2019

Когда это случилось со мной, это произошло из-за утечки памяти, вызванной статической переменной, израсходовавшей память.Я просматриваю все последние изменения кода и ищу возможные утечки памяти.

...