Jmap куча дамп, это молодое поколение? - PullRequest
5 голосов
/ 19 мая 2011

Быстрый вопрос

Включает ли дамп кучи jmap только старое поколение или также молодое поколение?


Подробное объяснение

У меня 2 дампа кучи (jmap -heap:format=b 9999):

  • один из моих серверов без нагрузки (без HTTP-запроса)
  • один при работе 50% ЦП, высокая загрузка (бенчмаркинг)

Теперь первый дамп показывает размер кучи больше, чем второй (что я думал странно).

Может ли это быть из-за того, что молодое поколение (при высокой нагрузке) часто меняется, потому что сборщик мусора часто работает (да, JVM почти заполнена)?Старое поколение заполнено на 99%, я заметил, что использование пространства молодым поколением сильно различается.

Так что это будет означать, что я сделал второй дамп сразу после того, как GC сделал свою работу, поэтому его размерменьшеЯ прав?

Дополнительная информация :

Java args:

-XX:+UseParallelGC -XX:+AggressiveHeap
-Xms2048m -Xmx4096m -XX:NewSize=64m
-XX:PermSize=64m -XX:MaxPermSize=512m

1 Ответ

10 голосов
/ 19 мая 2011

Быстрый ответ

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

Длинный ответ

Возможно, сборка мусора только что закончилась для 2-го процесса. Или наоборот, первый процесс, возможно, не имел полной коллекции в какое-то время и сидел на более высоком уровне памяти. Было ли это приложение / сервер только что перезапущено, когда вы сделали захват? Если вы посмотрите на бездействующий процесс, используя инструмент, подобный jvisualvm, вы увидите, что графики распределения памяти перемещаются вверх и вниз, даже если ваш процесс не выполняет никакой работы. Это просто JVM делает свое дело.

Обычно ваш полный сборщик мусора должен стартовать задолго до того, как он достигнет отметки 99% в старом поколении. JVM решит, когда запускать сборку полного сборщика мусора. Ваш молодой генерал будет часто колебаться, потому что именно здесь объекты создаются / удаляются быстрее всего. Будет много частичных сборов мусора, чтобы очистить молодого поколения, прежде чем запускать полноценный сборщик мусора. Разница между ними будет означать паузу в вашей деятельности JVM. Просмотр частичного ГК не повредит вашей заявке. Но время паузы полного GC остановит ваше приложение во время его работы. Таким образом, вы захотите свести к минимуму те, которые вы можете.

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

-XX:+PrintGCDetails -verbose:gc -Xloggc:/log/path/gc.log

Запустите вашу программу на некоторое время, а затем загрузите захваченный журнал в инструмент, чтобы помочь визуализировать результаты. Я лично использую Визуализатор сбора мусора и памяти , предлагаемый в IBM Support Assistant Workbench. Он предоставит вам сводку статистики по захваченной сборке мусора, а также динамический график, который вы можете использовать, чтобы увидеть, как ведет себя память в вашем приложении. Это не даст вам какие объекты были в вашей куче.

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

jmap -dump:format=b,file=/file/location/dump.hprof <pid>

Используя такой инструмент, как MAT , вы сможете увидеть все объекты, подозреваемых в утечках и другие статистические данные о поколениях, ссылки на кучу.

Редактировать для обсуждения настройки

Исходя из параметров запуска, вы можете попробовать несколько вещей

  • Установите ваши -Xms равными тому же значению как твой -Xmx. Делая это JVM не нужно тратить время на распределение больше кучи. Если вы ожидаете, что ваше приложение будет занимать 4 ГБ, сразу же предоставьте его
  • В зависимости от количества процессоров в системе вы используете это приложение, для которого вы можете установить флаг -XX:ParallelGCThreads=##.
  • Я не пробовал этот, но документация показывает параметр для -XX:+UseParallelOldGC, который показывает некоторое обещание сократить время старого GC коллекция.
  • Попробуйте изменить размер нового поколения на 1/4 кучи. (1024 вместо 64) Это может быть слишком сильным для старого поколения. Размер по умолчанию составляет около 30%, ваше приложение настроено на использование около 2% для молодого поколения. Хотя у вас не настроен максимальный размер, я беспокоюсь о том, что слишком много данных будет перенесено в старое поколение, потому что новое поколение слишком мало, чтобы обрабатывать все запросы. Таким образом, вы должны выполнить более полные (приостановленные) GC, чтобы очистить память.

В целом, я верю, что если вы выделяете столько памяти так быстро, то это может быть проблемой для поколения, когда память выделяется старому поколению преждевременно. Если настройка вашего нового размера gen не работает, вам нужно либо добавить больше кучи через конфигурацию -Xmx, либо сделать шаг назад и найти именно то, что удерживает память. Инструмент MAT, который мы обсуждали ранее, может показать вам ссылки, удерживающие объекты в памяти. Я бы порекомендовал сначала попробовать пункты 1 и 4. Это будет метод проб и ошибок для вас, чтобы получить правильные значения

...