Потребление памяти Tomcat больше, чем куча + пространство permgen - PullRequest
13 голосов
/ 07 ноября 2011

Я наблюдаю несоответствие в потреблении памяти Tomcat между тем, что говорит ОС, и тем, что говорит jVisualVM.

С htop у JVM Tomcat есть 993 МБ резидентной памяти

В jVisualVM JVM Tomcat использует

  • Макс. Кучи: 1,070,399,488 B
  • Размер кучи: 298.438.656 B
  • Используемая куча: переменная, от 170 МБ до 270 МБоколо 150 МБ

Насколько я понимаю, потребление памяти ОС должно быть размером кучи + размер PermGen ~ = 522 МБ.Но это 471 МБ меньше , чем то, что я наблюдаю.

Кто-нибудь понял, что мне здесь не хватает?

PS: я знаю, что моя максимальная куча намного выше, чем используемая, но я предполагаю, что это не должно иметь никакого эффекта, если JVM не использует ее (т. Е. Размер кучи ниже).

Спасибо!Marc

Ответы [ 4 ]

5 голосов
/ 07 ноября 2011

Насколько я понимаю, потребление памяти ОС должно быть размером кучи + размер PermGen ~ = 522 МБ.Но это на 471 МБ меньше, чем я наблюдаю.Кто-нибудь понял, что мне здесь не хватает?

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

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

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

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

  • Код дляреализовать JVM
  • ручную кучу C для структур данных, реализующих стеки JVM
  • для всех потоков в системе (приложение + JVM)
  • кэшированный байт-код Java (длябиблиотеки и приложения)
  • машинный код JIT (для библиотек и приложения)
  • Статические переменные всех загруженных классов
4 голосов
/ 07 ноября 2011

Первое, что мы должны иметь в виду, это: JVM process heap (OS process) = Java object heap + [Permanent space + Code generation + Socket buffers + Thread stacks + Direct memory space + JNI code + JNI allocated memory + Garbage collection], где в этом «наборе» permSpace обычно самый большой кусок.

Учитывая это, я полагаю, ключом здесь является опция JVM -XX:MinFreeHeapRatio=n, где n от 0 до 100, и это указывает, что куча должна быть расширена, если меньше, чем n% кучи свободно. Обычно это 40 по умолчанию (Sun), поэтому, когда JVM выделяет память, этого становится достаточно, чтобы получить 40% свободного ( это не применимо, если у вас есть -Xms == -Xmx ). Его «двойная опция» -XX: MaxHeapFreeRatio обычно по умолчанию равен 70 (вс).

Таким образом, в JVM Sun соотношение живых объектов в каждой сборке мусора находится в пределах 40-70%. Если после GC освобождается менее 40% кучи, то куча расширяется. Итак, предположим, что вы используете Sun JVM, я бы предположил, что размер «кучи объектов Java» достиг пика около 445 МБ, в результате чего расширенная «куча объектов» составляет около 740 МБ (чтобы гарантировать свободное 40%). , Тогда (куча объектов) + (пространство перманента) = 740 + 250 = 990 Мб.

Может быть, вы можете попытаться вывести детали GC или использовать jconsole, чтобы проверить эволюцию размера кучи.

P.S .: при работе с такими вопросами хорошо публиковать сведения об ОС и JVM.

3 голосов
/ 07 ноября 2011

Во время запуска вашего приложения JVM зарезервирует памяти, равной примерно размеру вашего значения кучи Макс (-Xmx), плюс еще немного для других вещей.Это препятствует тому, чтобы JVM возвращался к ОС, чтобы зарезервировать больше памяти позже.

Даже если ваше приложение использует только 298 МБ пространства кучи, 993 МБ все равно будет зарезервировано для ОС.Вам нужно будет прочитать больше в зарезервированной или выделенной памяти.

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

Если вам нужно больше подробностей, прочитайте статью Настройка сборки мусора Вот некоторые важныеИз документа

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

Также смотрите раздел 3.2 (iv)) в документе

При инициализации виртуальной машины зарезервировано все пространство для кучи.Размер зарезервированного пространства можно указать с помощью опции -Xmx.Если значение параметра -Xms меньше значения параметра -Xmx, не все зарезервированное пространство немедленно выделяется для виртуальной машины.

1 голос
/ 07 ноября 2011

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

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

Лучший способ узнать, что на самом деле делает ваша программа, - запустить jconsole и посмотреть, как там используется память. Это очень простой инструмент для просмотра памяти, который легко настроить.

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