Эта статья из:Технологическое сообщество PerfMa
Обзор проблемы
Вчера вечером мой коллега вдруг задал мне вопрос, почему System GC происходил сразу же после запуска системы (из журнала GC я видел, что GC Cause - это System GC), по моему опыту, это почти девять раз из десяти что не хватает памяти за пределами кучи.Вызвано,но при запуске не хватает,что кажется маловероятным,поэтому я и сказал,что сам звонил,и негде было настраивать.
Исходное местоположение проблемы
В данном случае скажу что отлаживать надо напрямую.Точка останова ставится на метод System.gc,чтобы при вызове этого метода был виден стек вызовов.После этой операции видно что это sun .misc.GC Вызывается в методе run внутреннего класса Daemon.
Конечно, если это производственная среда, вы не можете просто отладить. Мы также можем видеть стек вызовов с помощью таких инструментов, как btrace. Есть еще много способов.
Демонстрационная репродукция
Когда я увидел стек вызовов, я сразу подумал об RMI. Наша система использует RMI, потому что эта система будет взаимодействовать с удаленными процессами через RMI. По моему опыту, RMI будет регулярно выполнять системный GC. Время по умолчанию — один час. параметры для этого интервала следующие два:
-Dsun.rmi.dgc.client.gcInterval=36000000
-Dsun.rmi.dgc.server.gcInterval=36000000
Чтобы упростить поиск и устранение неполадок, я написал демонстрацию для имитации
Чтобы запустить вышеуказанную программу, мы случайным образом запускаем java-процесс локально, а затем получаем соответствующий номер процесса, который передается вышеуказанной программе в качестве первого параметра программы. Мы можем добавить несколько параметров JVM для печати журнала GC и весь запуск Команда, вероятно,
анализ проблемы
Верно, что в приведенной выше демонстрации лошадь все еще воспроизводится.Это не значение по умолчанию для СИСТЕМНОГО GC.Как я могу получить СИСТЕМНЫЙ GC?
Предполагается, что некоторые люди догадались об RMI и знают, что вышеуказанные параметры могут управлять интервалом GC.Что касается того, почему Системный GC срабатывает сразу, я раньше этого не замечал, но после анализа реальная ситуация далека от вас. Видя эту ситуацию, реальная ситуация такова, что это может произойти сразу или время от времени, в зависимости от вашего алгоритма GC, в зависимости от времени перезапуска вашей операционной системы, вам все интереснее это слышать?
Хорошо, давайте начнем наше путешествие по анализу, давайте сначала посмотрим на метод запуска нашего демона.
Среди них maxObjectInspectionAge — нативный метод.При его первом выполнении можно считать, что значение latencyTarget равно одному часу, то есть 36000000. Запускает ли это Sysmte GC, зависит от того, больше ли значение, возвращаемое maxObjectInspectionAge. чем через час. Через час немедленно запускается System GC, и теперь основное внимание уделяется нативному методу maxObjectInspectionAge.
Из вышеприведенной логики, наверное, видно, когда последний GC этой кучи.Для удобства разбора буду напрямую использовать логику под CMS GC.Другие алгоритмы GC аналогичны.
Во-первых, берется наносекундное время.Приобретение этого наносекундного времени также связано с операционной системой.Приведу пример под linux.
Если linux поддерживает CLOCK_MONOTONIC, возвращаемое значение представляет собой относительные наносекунды с момента запуска операционной системы до настоящего времени. Я не буду много говорить о CLOCK_MONOTONIC. Вы можете искать несколько часов, определенных POSIX. Мы тестируем работающую систему. Это поддерживается, поэтому количество наносекунд относительно запуска операционной системы будет возвращено напрямую.
Затем пройдите время последнего GC нового поколения и старого поколения
Получение этого времени тоже одинаковое.Оно получается с помощью os::javaTimeNanos, что примерно означает, что время восстановления нового поколения и старого поколения относительно раннее.Например, если я делаю GC сначала старое поколение, оно обновит старое поколение_time_of_last_gc
Переменная — это текущее количество наносекунд, а сборщик мусора нового поколения будет сделан позже, и новое поколение будет обновлено._time_of_last_gc
Переменная представляет собой текущую наносекундную книгу, тогда возвращаемое время будет старым поколением._time_of_last_gc
Значение переменной, на этот раз временно названное t2, поэтому собственный метод maxObjectInspectionAge выше возвращает разницу во времени между текущим временем в наносекундах и t2, поэтому, когда разница во времени превышает 1 час, будет выполняться System GC.
Эта проблема здесь, если мы никогда не случались ранее, или только один GC, такой как только YGC, или только старый GC, значение T2 выше связано с алгоритмом GC, в GC PS GC, значение настройки по умолчанию 0,
jlong PSParallelCompact::_time_of_last_gc = 0;
jlong PSMarkSweep::_time_of_last_gc = 0;
Но под CMS GC мы видим, что нет ни инициализации, ни инициализации, это значение неопределенное, и оно связано с компилятором
Итак, здесь я беру более надежный алгоритм PS в качестве примера.
-
Если операционная система работает более часа, первый системный сборщик мусора будет запущен немедленно.
-
Если ОС проработала 20 минут, первая сборка мусора Sysmte будет запущена через 40 минут.
вывод проблемы
Так что, когда мы видим срабатывание System GC, помимо уже знакомых сценариев, первое срабатывание System GC в сценарии RMI также определяется многими факторами, надеюсь, эта статья будет полезна всем.
Говоря о System GC, я полагаю, что некоторые люди подумают о параметре JVM DisableExplicitGC. Включив этот параметр, можно отключить появление System GC. Однако я не рекомендую вам устанавливать этот параметр. Поскольку JVM хочет сделать System GC, это необходимо сделать.Риск прямого запрета может быть больше.Для того, чтобы все лучше понимали принцип реализации параметров JVM, недавно вPerfMaСообщество, дать вам подробное объяснение параметров JVM.
Давайте учиться вместе:
Параметры JVM серии PerfMa KO [Память]
«Странная» проблема с загрузкой кеша JVM, устранение неполадок