Все, что вам нужно знать о System.gc()

В этой статье мы попытались ответить на наиболее распространенные вопросы, связанные с вызовом API System.gc(). Мы надеемся, что это может помочь.

Что такое System.gc()?
System.gc() — это API, предоставляемый в java, Android, C# и других популярных языках. При вызове он приложит все усилия, чтобы очистить память от накопленных объектов, на которые нет ссылок (т. е. мусора).

Кто вызывает System.gc()?
Вызовы System.gc() можно вызывать из различных частей стека вашего приложения:

а). Разработчики ваших собственных приложений могут явно вызывать метод System.gc().
б). Иногда System.gc() может запускаться вашими сторонними библиотеками, фреймворками, иногда даже вашими серверами приложений.
в). Его можно запустить из внешних инструментов (например, VisualVM) с помощью JMX.
г). Если ваше приложение использует RMI, то RMI периодически вызывает System.gc().

Каковы недостатки вызова System.gc()?

Когда вызовы API System.gc() или Runtime.getRuntime().gc() вызываются из вашего приложения, будут инициированы события Stop-the-world Full GC. Во время полного GC с остановкой мира вся JVM будет заморожена (т. е. все транзакции клиента, которые находятся в движении, будут приостановлены). Как правило, эти полные сборщики мусора занимают много времени. Таким образом, это может привести к плохому взаимодействию с пользователем и вашим соглашениям об уровне обслуживания в ненужное время, когда запуск сборщика мусора не требуется.

JVM имеет сложный алгоритм, работающий все время в фоновом режиме, выполняя все вычисления и расчеты того, когда запускать GC. Когда вы вызываете вызов System.gc(), все эти вычисления будут отброшены. Что, если JVM инициировала событие GC всего за миллисекунду назад, а вы снова из своего приложения вызываете System.gc()? Потому что из вашего приложения вы не знаете, когда запускался сборщик мусора.

Есть ли веские/действительные причины для вызова System.gc()?

Мы не встречали столько веских причин для вызова System.gc() из приложения. Но вот интересный вариант использования, который мы видели в приложении крупной авиакомпании. Это приложение использует 1 ТБ памяти. Время паузы полного GC в этом приложении занимает около 5 минут. Да, не удивляйтесь, это 5 минут 🙂 (но мы видели случаи и с 23-минутной паузой GC). Чтобы избежать каких-либо последствий для клиентов из-за этой паузы, эта авиакомпания внедрила умное решение. Каждую ночь они извлекают по одному экземпляру JVM из своего пула балансировщика нагрузки. Затем они явно вызывают вызов System.gc() через JMX на этой JVM. После завершения события GC и удаления мусора из памяти они возвращают эту JVM в пул балансировщика нагрузки. Благодаря этому умному решению они свели к минимуму воздействие на клиентов, вызванное 5-минутной паузой GC.

Как определить, выполняются ли вызовы System.gc() из вашего приложения?

Как вы можете заметить в разделе «Кто вызывает System.gc()?» В разделе вы можете увидеть вызовы System.gc() из нескольких источников, а не только из исходного кода вашего приложения. Таким образом, поиска в коде вашего приложения строки «System.gc()» недостаточно, чтобы определить, выполняет ли ваше приложение вызовы System.gc(). Таким образом, возникает проблема: как определить, вызываются ли вызовы System.gc() во всем стеке вашего приложения?

Вот где журналы GC пригодятся. Включить журналы GC в вашем приложении. На самом деле рекомендуется постоянно держать журнал GC включенным на всех рабочих серверах, поскольку это помогает устранять неполадки и оптимизировать производительность приложений. Включение журналов GC добавляет незначительные (если вообще заметные) накладные расходы. Теперь загрузите свой журнал сборщика мусора в инструмент анализа журнала сбора мусора, например GCeasy, HP JMeter,…. Эти инструменты создают подробный отчет об анализе сбора мусора.

gc-причины.PNG
Рис. GC Causes, о которых сообщает инструмент GCeasy.io

На приведенном выше рисунке представлена ​​выдержка из раздела «Причины GC» отчета, созданного GCeasy. Вы можете видеть, что вызов System.gc() вызывается 304 раза, что составляет 52,42% времени паузы GC.

Как удалить вызовы System.gc()?
Вы можете удалить явный вызов System.gc() с помощью следующих решений:

а. Поиск и замена

Это может быть традиционный метод 😃, но это работает. Найдите в кодовой базе вашего приложения «System.gc()» и «Runtime.getRuntime().gc()». Если вы видите совпадение, то удалите его. Это решение будет работать, если «System.gc()» вызывается из исходного кода вашего приложения. Если «System.gc()» будет вызываться из ваших сторонних библиотек, фреймворков или внешних источников, это решение не будет работать. В таких обстоятельствах вы можете рассмотреть возможность использования варианта, описанного в #b.

б. -XX:+DisableExplicitGC

Вы можете принудительно отключить вызовы System.gc(), передав аргумент JVM ‘-XX:+DisableExplicitGC’ при запуске приложения. Эта опция отключит все вызовы System.gc(), которые вызываются где угодно из стека вашего приложения.

против. РМИ

Если ваше приложение использует RMI, вы можете управлять частотой вызовов System.gc(). Эту частоту можно настроить с помощью следующих аргументов JVM при запуске приложения:

-Dsun.rmi.dgc.server.gcInterval=n

-Dsun.rmi.dgc.client.gcInterval=n

Значение по умолчанию для этих свойств в

JDK 1.4.2 и 5.0 составляет 60000 миллисекунд (т.е. 60 секунд).

JDK 6 и более поздние версии составляют 3600000 миллисекунд (т.е. 60 минут).

Возможно, вы захотите установить для этих свойств очень высокое значение, чтобы свести к минимуму влияние.

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *