Рубрики
Без рубрики

Журналы сборки мусора Java и как их анализировать

При работе с Java или любым другим языком программирования на основе JVM мы получаем определенные функциональные возможности для… Помеченный как java, gc, журналы, наблюдаемость.

При работе с Java или любым другим языком программирования на основе JVM мы получаем определенные функции бесплатно. Одной из таких функций является очистка памяти. Если вы когда-либо использовали такие языки, как C/C++, вы, вероятно, помните такие функции, как каллок , перераспределить и бесплатно . Нам нужно было позаботиться о назначении каждого байта в памяти и освободить выделенную память, когда она больше не нужна. Без этого мы вскоре столкнулись с нехваткой памяти, что привело к нестабильности и сбоям.

С Java нам не нужно беспокоиться об освобождении памяти, которая была назначена объекту. Нам нужно только прекратить использовать объект. Все очень просто. Как только на объект больше не ссылаются из нашего кода, память может быть освобождена и использована повторно.

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

Виртуальная машина Java запускает сборщик мусора в фоновом режиме, чтобы найти ссылки, которые не используются. Память, используемая такими ссылками, может быть освобождена и использована повторно. Вы уже можете видеть разницу по сравнению с такими языками, как C/C++. Вам не нужно помечать объект для удаления, достаточно прекратить его использование.

Память кучи также разделена на разные области, и каждая из них имеет свой собственный тип сборщика мусора. Существует несколько реализаций сборщика мусора, и каждая JVM может иметь свою собственную реализацию, если она соответствует спецификации. В теории и на практике каждый поставщик JVM может предоставить свою собственную реализацию сборщика мусора, обеспечивающую различную производительность.

Упрощенный вид трех основных областей кучи JVM можно визуализировать следующим образом:

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

Журнал сборщика мусора представляет собой текстовый файл, созданный виртуальной машиной Java, который описывает работу сборщика мусора. Он содержит всю информацию, необходимую вам, чтобы увидеть, как работает процесс очистки памяти. Он также показывает, как ведет себя сборщик мусора и сколько ресурсов он использует. Хотя мы можем отслеживать наше приложение с помощью поставщика APM или встроенного инструмента мониторинга, журнал сборщика мусора будет бесценен для быстрого выявления любых потенциальных проблем и узких мест, когда дело доходит до использования кучи памяти.

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

2019-10-29T10:00:28.693-0100: 0.302: [GC (Allocation Failure) 2019-10-29T10:00:28.693-0100: 0.302: [ParNew
Desired survivor size 1114112 bytes, new threshold 1 (max 6)
- age   1:    2184256 bytes,    2184256 total
: 17472K->2175K(19648K), 0.0011358 secs] 17472K->2382K(63360K), 0.0012071 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
2019-10-29T10:00:28.694-0100: 0.303: Total time for which application threads were stopped: 0.0012996 seconds, Stopping threads took: 0.0000088 seconds
2019-10-29T10:00:28.879-0100: 0.488: Total time for which application threads were stopped: 0.0001006 seconds, Stopping threads took: 0.0000065 seconds
2019-10-29T10:00:28.897-0100: 0.506: Total time for which application threads were stopped: 0.0000981 seconds, Stopping threads took: 0.0000076 seconds
2019-10-29T10:00:28.910-0100: 0.519: Total time for which application threads were stopped: 0.0000896 seconds, Stopping threads took: 0.0000062 seconds
2019-10-29T10:00:28.923-0100: 0.531: Total time for which application threads were stopped: 0.0000975 seconds, Stopping threads took: 0.0000069 seconds
2019-10-29T10:00:28.976-0100: 0.585: Total time for which application threads were stopped: 0.0001414 seconds, Stopping threads took: 0.0000091 seconds
2019-10-29T10:00:28.982-0100: 0.590: [GC (Allocation Failure) 2019-10-29T10:00:28.982-0100: 0.590: [ParNew
Desired survivor size 1114112 bytes, new threshold 1 (max 6)
- age   1:    1669448 bytes,    1669448 total
: 19647K->2176K(19648K), 0.0032520 secs] 19854K->5036K(63360K), 0.0033060 secs] [Times: user=0.03 sys=0.00, real=0.00 secs]

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

Работа с настройкой производительности приложений может быть долгим и неприятным занятием. Нам нужно правильно подготовить окружающую среду и соблюдать правила применения. Проверьте это, чтобы узнать больше о Настройке производительности JVM . С помощью правильного инструмента наблюдения, такого как наше Sematext Cloud , вы получаете представление о важнейших показателях , связанных с приложением, JVM и операционной системой.

Однако метрики – это еще не все. Даже самые лучшие инструменты APM не дадут вам всего. Metrics может показать вам шаблоны и исторические данные, которые помогут вам выявить потенциальные проблемы, но чтобы иметь возможность увидеть все, вам нужно копнуть глубже. Этот более глубокий уровень с точки зрения приложения на базе Java – это журнал сборки мусора. Несмотря на то, что журналы GC очень подробны, они предоставляют информацию, которая недоступна в других источниках, например, события остановки мира и сколько времени они заняли, как долго были остановлены потоки приложений, использование пула памяти и многое, многое другое.

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

У вас всегда должны быть включены журналы сборки мусора Java. На самом деле, многие системы с открытым исходным кодом уже следуют этой практике. Например, поисковые системы, такие как Apache Solr или Elasticsearch уже включают флаги JVM, которые включают журналы. Мы уже знаем, что эти файлы содержат важную информацию об операциях виртуальной машины Java, поэтому мы знаем, почему мы должны ее включить.

Существует разница в том, как вы активируете ведение журнала сборки мусора для Java 8 и более ранних версий, а также для более новых версий Java.

Для Java 8 и более ранних версий вам следует добавить следующие флаги в параметры запуска вашего приложения на основе JVM:

-XX:+PrintGCDetails -Xloggc:

Где PATH_TO_GC_LOG_FILE – это расположение файла журнала сборщика мусора. Например:

java -XX:+PrintGCDetails -Xloggc:/var/log/myapp/gc.log -jar my_awesome_app.jar

В некоторых случаях вы также можете видеть, что -XX:+PrintGCTimeStamps включен. Однако здесь это излишне и не нужно.

Для Java 9 и новее вы можете упростить приведенную выше команду и добавить следующий флаг в параметры запуска приложения:

-Xlog:gc*:file=

Например:

java -Xlog:gc*:file=/var/log/myapp/gc.log -jar my_awesome_app.jar

Как только вы включите журналы, важно помнить о ротации журналов GC. При использовании более старой версии JVM, такой как JDK 8, вы можете захотеть повернуть свои журналы GC. Для этого у нас есть три флага, которые мы можем добавить к параметрам запуска нашего приложения JVM. Первый из них – это флаг, который позволяет вращать журналы GC: -XX:+UseGCLogFileRotation . Второе свойство -XX:NumberOfGCLogFiles сообщает JVM, сколько файлов журнала GC должно храниться. Например, включение -XX:NumberOfGCLogFiles=10 позволит включить до 10 файлов журнала GC. Наконец, -XX:GCLogFileSize указывает, насколько большим может быть один файл журнала GC. Например -XX:GCLogFileSize=10m будет вращать файл журнала GC, когда он достигнет 10 мегабайт.

При использовании JDK 11 и сборщика мусора G1GC для управления вашими журналами GC вам потребуется включить свойство, подобное этому: java . Это приведет к точно такому же поведению. у нас будет до 10 файлов журнала GC размером до 10 мегабайт.

Теперь, когда мы знаем, насколько важны журналы сборщика мусора JVM, и мы включили их по умолчанию, мы можем начать их анализировать.

Разобраться в журналах сбора мусора непросто. Это требует понимания того, как работает виртуальная машина Java, и понимания использования памяти приложением. В этом сообщении в блоге мы пропустим анализ приложения, поскольку он отличается от приложения к приложению и требует знания кода. Однако мы обсудим, как читать и анализировать журналы сборки мусора, которые мы можем получить из JVM.

Что также очень важно, так это то, что существуют различные версии JVM и несколько реализаций сборщика мусора. Вы все еще можете столкнуться с Java 7, 8, 9 и так далее. Некоторые компании по-прежнему используют Java 6 по разным причинам. В каждой версии могут быть запущены разные сборщики мусора — Последовательные, параллельные, Параллельные Mark Sweep, G1 или даже Shenandoah или Z. Вы можете ожидать, что разные версии Java и разные реализации сборщика мусора будут выдавать немного другой формат журнала, и, конечно, мы не будем обсуждать их все. На самом деле, мы покажем вам лишь небольшую часть журналов, но такую, которая должна помочь вам также понять все другие журналы сборщика мусора.

Журналы сбора мусора смогут ответить на такие вопросы, как:

  • Когда использовался сборщик мусора молодого поколения?
  • Когда использовался сборщик мусора старого поколения?
  • Сколько было запущено сборок мусора?
  • Как долго работали сборщики мусора?
  • Каково было использование памяти до и после сборки мусора?

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

Давайте начнем с рассмотрения Java 8 и параллельного сборщика мусора для пространства молодого поколения и параллельного сборщика мусора Mark Sweep для старого поколения. Одна строка, исходящая из нашего сборщика мусора JVM, может выглядеть следующим образом:

2019-10-30T11:13:00.920-0100: 6.399: [Full GC (Allocation Failure) 2019-10-30T11:13:00.920-0100: 6.399: [CMS: 43711K->43711K(43712K), 0.1417937 secs] 63359K->48737K(63360K), [Metaspace: 47130K->47130K(1093632K)], 0.1418689 secs] [Times: user=0.14 sys=0.00, real=0.14 secs]

Прежде всего, вы можете увидеть дату и время события, которое в нашем случае 2019-10–30T11:13:00.920–0100 . Это время, когда произошло событие, чтобы вы могли видеть, что произошло и когда это произошло.

Следующее, что мы можем увидеть в приведенной выше строке журнала, – это тип сборки мусора. В нашем случае это полный GC, и вы также можете ожидать GC в качестве значения здесь. Существует три типа событий сборщика мусора, которые могут произойти:

  • Незначительная уборка мусора
  • Крупный сбор мусора
  • Полная сборка мусора

Незначительная сборка мусора означает, что молодое поколение событие очистки пространства было выполнено JVM. Младший сборщик мусора всегда будет запускаться, когда недостаточно памяти для выделения нового объекта в куче, т.Е. когда поколение Eden заполнено или приближается к заполнению. Если ваше приложение создает новые объекты очень часто, вы можете ожидать, что младший сборщик мусора будет часто запускаться. Что вы должны помнить, так это то, что во время незначительной сборки мусора при очистке пространств Eden и survivor данные копируются полностью, что означает, что фрагментации памяти не произойдет.

Основная сборка мусора означает, что было выполнено событие постоянной генерации очистки. Штатное поколение также широко называют пространством старого поколения. В зависимости от сборщика мусора и его настроек постоянная очистка поколения может происходить реже или чаще. Что лучше? Правильный ответ зависит от варианта использования, и мы не будем освещать это в этом сообщении в блоге.

Java Full GC |/означает, что произошло событие полной сборки мусора. Это означает, что как молодое , так и старое поколение было очищено. Сборщик мусора попытался очистить его, и журнал сообщает нам, что Для постоянной очистки поколения требуются фазы разметки, развертки и сжатия, чтобы избежать большого объема памяти Если сборщик мусора не будет заботиться о фрагментации памяти, вы можете оказаться в ситуации, когда у вас достаточно памяти, но она фрагментирована, и объект не может быть выделен. Мы можем проиллюстрировать эту ситуацию следующей диаграммой:

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

Следующая важная вещь в строке журнала – это информация о занятии памяти до и после процесса сборки мусора. Давайте еще раз рассмотрим эту линию более подробно:

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

Одна часть очень важной информации, которую предоставляет нам сборщик мусора JVM, – это общее время, на которое останавливаются потоки приложения. Вы можете ожидать, что потоки будут останавливаться очень часто, но на очень короткий промежуток времени. Например:

2019-10-29T10:00:28.879-0100: 0.488: Total time for which application threads were stopped: 0.0001006 seconds, Stopping threads took: 0.0000065 seconds

Вы можете видеть, что потоки были остановлены на 0,0001006 секунды, а остановка потоков заняла 0,0000065 секунды. Это не займет много времени для остановки потоков, и вы будете видеть подобную информацию снова и снова в своих журналах сборщика мусора. Что должно вызвать красный флаг, так это длительное время остановки потока, также называемое событием stop the world, которое в основном остановит ваше приложение. Что должно вызвать красный флаг, так это длительное время остановки потока, также называемое событием stop the world, которое в основном остановит ваше приложение.

2019-11-02T17:11:54.259-0100: 7.438: Total time for which application threads were stopped: 11.2305001 seconds, Stopping threads took: 0.5230011 seconds

В приведенной выше строке журнала мы видим, что потоки приложения были остановлены более чем на 11 секунд. Что это значит? По сути, ваше приложение не отвечало более 11 секунд. Он не отвечал ни на какие запросы, не обрабатывал данные, а JVM выполняла только сборку мусора. Вы хотите избежать подобных ситуаций любой ценой. Вы хотите избежать подобных ситуаций любой ценой. Либо у вас слишком мало памяти, чтобы ваше приложение могло должным образом выполнять свою работу, либо у вас утечка памяти, которая заполняет ваше пространство в куче, что в конечном итоге приводит к длительной сборке мусора и, наконец, к нехватке памяти. Это означает, что ваши приложения не смогут создавать новые объекты и перестанут работать.

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

  • -XX:+UseG1GC
  • -XX:-useconcon marksweepgc
  • -XX:-Используйте только инициирующее занятие

Итак, мы включаем сборщик мусора G1 и удаляем одновременную очистку меток.

Стандартная запись журнала сборщика мусора G1 выглядит следующим образом:

2019-11-03T21:26:21.827-0100: 2.069: [GC pause (G1 Evacuation Pause) (young)
Desired survivor size 2097152 bytes, new threshold 15 (max 15)
- age   1:     341608 bytes,     341608 total
, 0.0021740 secs]
   [Parallel Time: 0.9 ms, GC Workers: 10]
      [GC Worker Start (ms): Min: 2069.4, Avg: 2069.5, Max: 2069.6, Diff: 0.1]
      [Ext Root Scanning (ms): Min: 0.1, Avg: 0.2, Max: 0.4, Diff: 0.3, Sum: 1.5]
      [Update RS (ms): Min: 0.1, Avg: 0.2, Max: 0.3, Diff: 0.2, Sum: 2.3]
         [Processed Buffers: Min: 1, Avg: 1.4, Max: 4, Diff: 3, Sum: 14]
      [Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
      [Object Copy (ms): Min: 0.2, Avg: 0.3, Max: 0.3, Diff: 0.1, Sum: 3.0]
      [Termination (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
         [Termination Attempts: Min: 1, Avg: 1.0, Max: 1, Diff: 0, Sum: 10]
      [GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
      [GC Worker Total (ms): Min: 0.6, Avg: 0.7, Max: 0.8, Diff: 0.1, Sum: 7.0]
      [GC Worker End (ms): Min: 2070.2, Avg: 2070.2, Max: 2070.2, Diff: 0.0]
   [Code Root Fixup: 0.0 ms]
   [Code Root Purge: 0.0 ms]
   [Clear CT: 0.2 ms]
   [Other: 1.1 ms]
      [Choose CSet: 0.0 ms]
      [Ref Proc: 0.8 ms]
      [Ref Enq: 0.0 ms]
      [Redirty Cards: 0.2 ms]
      [Humongous Register: 0.0 ms]
      [Humongous Reclaim: 0.0 ms]
      [Free CSet: 0.0 ms]
   [Eden: 26.0M(26.0M)->0.0B(30.0M) Survivors: 5120.0K->3072.0K Heap: 51.4M(64.0M)->22.6M(64.0M)]
 [Times: user=0.01 sys=0.00, real=0.01 secs]

В приведенной выше строке журнала вы можете видеть, что у нас было мероприятие по сбору мусора для молодого поколения [Пауза GC (Пауза эвакуации G1) (young) , в результате которой были очищены определенные области памяти: [Eden: 26.0M(26.0M)->0.0B(30.0M) Выжившие: 5120.0K->3072.0K Куча: 51.4M(64.0M)->22,6М(64,0М)] . У нас также есть информация о времени и использовании процессора [Время:.01.00,.01 сек.] . Тайминги точно такие же, как и в предыдущем обсуждении сборки мусора. Пользователь и система отслеживают использование ЦП во время процесса сборки мусора, и у нас есть время, которое на это ушло.

Сводка информации о памяти является подробной и дает нам общее представление о том, что произошло. Мы видим, что пространство Eden было полностью очищено Eden: 26.0M(26.0M)->0.0B(30.0M) . Сборка мусора началась, когда он был занят 26 миллионами данных. После сбора мусора мы закончили с совершенно пустым пространством Eden. Общий размер пространства Eden на момент сбора мусора составлял 30 МБ. Сборка мусора началась с того, что в пространстве выживших было 5120 Кб памяти, а закончилась 3072 Кб данных. Наконец, вся куча началась с 51,4 М занятого из общего размера 64 М и закончилась 22,6 М занятого.

В дополнение к этому вы также увидите более подробную информацию о внутренних компонентах рабочих параллельных сборщиков мусора и этапах их работы — таких как запуск, сканирование и работа.

Вы также можете просмотреть дополнительные записи журнала, связанные со сборщиком мусора G1:

2019-11-03T21:26:23.704-0100: 2019-11-03T21:26:23.704-0100: 3.946: 3.946: [GC concurrent-root-region-scan-start]
Total time for which application threads were stopped: 0.0035771 seconds, Stopping threads took: 0.0000111 seconds
2019-11-03T21:26:23.706-0100: 3.948: [GC concurrent-root-region-scan-end, 0.0017994 secs]
2019-11-03T21:26:23.706-0100: 3.948: [GC concurrent-mark-start]
2019-11-03T21:26:23.737-0100: 3.979: [GC concurrent-mark-end, 0.0315921 secs]
2019-11-03T21:26:23.737-0100: 3.979: [GC remark 2019-11-03T21:26:23.737-0100: 3.979: [Finalize Marking, 0.0002017 secs] 2019-11-03T21:26:23.738-0100: 3.980: [GC ref-proc, 0.0004151 secs] 2019-11-03T21:26:23.738-0100: 3.980: [Unloading, 0.0025065 secs], 0.0033738 secs]
 [Times: user=0.04 sys=0.01, real=0.01 secs]
2019-11-03T21:26:23.741-0100: 3.983: Total time for which application threads were stopped: 0.0034705 seconds, Stopping threads took: 0.0000308 seconds
2019-11-03T21:26:23.741-0100: 3.983: [GC cleanup 54M->54M(64M), 0.0004419 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs]

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

Мы можем даже углубиться в сборку мусора и включить уровень отладки. Давайте возьмем Java 10 в качестве примера и включим -Xlog:gc*,gc+phases=debug в параметры запуска JVM. Это включит ведение журнала на уровне отладки для этапов сборки мусора для сборщика мусора G1 по умолчанию в Java 10. Это позволит вести подробное ведение журнала GC, предоставляя вам обширную информацию о работе сборщика мусора.

[0.006s][info][gc,heap] Heap region size: 1M
[0.012s][info][gc     ] Using G1
[0.013s][info][gc,heap,coops] Heap address: 0x00000006c0000000, size: 4096 MB, Compressed Oops mode: Zero based, Oop shift amount: 3
[0.428s][info][gc,start     ] GC(0) Pause Young (G1 Evacuation Pause)
[0.428s][info][gc,task      ] GC(0) Using 2 workers of 2 for evacuation
[0.432s][info][gc,phases    ] GC(0)   Pre Evacuate Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Prepare TLABs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Choose Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Humongous Register: 0.0ms
[0.433s][info ][gc,phases    ] GC(0)   Evacuate Collection Set: 3.8ms
[0.433s][debug][gc,phases    ] GC(0)     Ext Root Scanning (ms):   Min:  0.6, Avg:  0.7, Max:  0.8, Diff:  0.2, Sum:  1.4, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Update RS (ms):           Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Processed Buffers:        Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Scanned Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Skipped Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Scan RS (ms):             Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Scanned Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Claimed Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Skipped Cards:            Min: 0, Avg:  0.0, Max: 0, Diff: 0, Sum: 0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Code Root Scanning (ms):  Min:  0.0, Avg:  0.1, Max:  0.1, Diff:  0.1, Sum:  0.1, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     AOT Root Scanning (ms):   skipped
[0.433s][debug][gc,phases    ] GC(0)     Object Copy (ms):         Min:  2.8, Avg:  2.9, Max:  3.0, Diff:  0.2, Sum:  5.7, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     Termination (ms):         Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)       Termination Attempts:     Min: 1, Avg:  1.0, Max: 1, Diff: 0, Sum: 2, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     GC Worker Other (ms):     Min:  0.0, Avg:  0.0, Max:  0.0, Diff:  0.0, Sum:  0.0, Workers: 2
[0.433s][debug][gc,phases    ] GC(0)     GC Worker Total (ms):     Min:  3.6, Avg:  3.6, Max:  3.7, Diff:  0.1, Sum:  7.3, Workers: 2
[0.433s][info ][gc,phases    ] GC(0)   Post Evacuate Collection Set: 0.1ms
[0.433s][debug][gc,phases    ] GC(0)     Code Roots Fixup: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Preserve CM Refs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Reference Processing: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Clear Card Table: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Reference Enqueuing: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Merge Per-Thread State: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Code Roots Purge: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Redirty Cards: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     DerivedPointerTable Update: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Free Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Humongous Reclaim: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Start New Collection Set: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Resize TLABs: 0.0ms
[0.433s][debug][gc,phases    ] GC(0)     Expand Heap After Collection: 0.0ms
[0.433s][info ][gc,phases    ] GC(0)   Other: 0.2ms
[0.433s][info ][gc,heap      ] GC(0) Eden regions: 7->0(72)
[0.433s][info ][gc,heap      ] GC(0) Survivor regions: 0->1(1)
[0.433s][info ][gc,heap      ] GC(0) Old regions: 0->1
[0.433s][info ][gc,heap      ] GC(0) Humongous regions: 6->3
[0.433s][info ][gc,metaspace ] GC(0) Metaspace: 9281K->9281K(1058816K)
[0.433s][info ][gc           ] GC(0) Pause Young (G1 Evacuation Pause) 13M->4M(122M) 4.752ms
[0.433s][info ][gc,cpu       ] GC(0) User=0.00s Sys=0.01s Real=0.00s

Вы можете увидеть точное время в разделе с подсветкой в строке журнала выше. Они отсутствовали в журнале сборщика мусора G1, который мы обсуждали ранее. Конечно, фазы – это не единственная опция, которую вы можете включить. Это параметры, которые стали доступны с Java 9 и здесь соответствуют флагам, которые были удалены или устарели. Вот некоторые из опций, доступных в более ранних версиях виртуальной машины Java, и параметры, которые они преобразуют в Java 9 и более поздних версиях:

  • -XX:+PrintHeapAtGC теперь может быть выражен как -Xlog:gc+heap=debug вариант
  • -XX:+printparalleloldgcфазы могут быть выражены как -Xlog:gc+фазы*=трассировка
  • -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationConcurrentTime gc+регион*=трассировка
  • -XX:+SummarizeConcMark может быть выражен как -Xlog: gc+маркировка*=трассировка
  • -XX:+Статистика набора сумматора может быть выражена как -Xlog:gc+remset*=трассировка
  • -XX:+PrintJNIGCStalls может быть выражен как -Xlog: gc+jni*=отладка
  • -XX:+Очередь задач печати может быть выражена как -Xlog:gc+задача+статистика*=трассировка
  • -XX:+Трассировка динамических потоков GC может быть выражена как -Xlog:gc+task*=трассировка
  • -XX:+PrintAdaptiveSizePolicy может быть выражен как -Xlog:gc+ergo*=трассировка
  • -XX:+PrintTenuringDistribution может быть выражено как -Xlog:gc+age*=трассировка

Вы можете объединить несколько параметров или включить их все, добавив флаг -Xlog:all=trace в параметры запуска вашего приложения JVM. Но имейте в виду, что это может привести к довольно большому количеству информации в файлах журнала сборщика мусора. Чтобы избежать потока информации, вы можете настроить его на отладку с помощью -Xlog:all =debug — это уменьшит объем информации, но даст вам намного больше, чем стандартный журнал сборщика мусора.

Существуют инструменты анализа журналов , которые могут помочь вам проанализировать журналы сборщика мусора. Ничего доступного из коробки в стандартном дистрибутиве виртуальной машины Java через.

Когда дело доходит до наблюдения за высокоуровневым обзором производительности сборщика мусора Java, вы можете использовать один из инструментов observability, обеспечивающих мониторинг на уровне приложений Java. Например, наш собственный мониторинг Sematext JVM , предоставляемый Sematext Cloud .

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

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

Например, одним из инструментов, который может помочь вам визуализировать журналы GC, является GCViewer . Инструмент, который позволяет анализировать журналы сборщика мусора до Java 1.5 и его продолжения , нацеленный на поддержку более новых версий Java и сборщика мусора G1.

Средство просмотра GC предназначено для предоставления исчерпывающей информации об использовании памяти и процессе сборки мусора в целом. Он имеет открытый исходный код и полностью бесплатен для личного и коммерческого использования с целью обеспечения поддержки вплоть до Java 8 включительно и с унифицированным ведением журнала для OpenJDK 9 и 10.

Существуют также инструменты, которые являются проприетарными и коммерческими. Одним из них является GC Easy . Это онлайн-инструмент GC log analyzer, в который вы можете загрузить журнал сбора мусора и получить результаты в виде удобного для чтения отчета об анализе журнала:

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

Несмотря на то, что у GC Easy есть бесплатный план, он ограничен. На момент написания статьи один пользователь мог загружать 5 файлов журнала GC в месяц объемом до 50 Мб на файл. Существуют дополнительные планы, доступные, если вы заинтересованы в использовании этого инструмента.

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

Оригинал: “https://dev.to/sematext/java-garbage-collection-logs-how-to-analyze-them-4hgb”