Подтвердить что ты не робот

Потребление памяти Tomcat больше, чем куча + пространство

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

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

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

  • Куча Макс: 1,070,399,488 B
  • Размер кучи: 298.438.656 B
  • Используемая куча: переменная, между 170 МБ и 270 МБ
  • PermGen Max: 268 435 456 B
  • PermGen Размер: 248,872,960 B
  • PermGen Используется: слегка переменная, около 150 МБ

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

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

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

Спасибо! Марк

4b9b3361

Ответ 1

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

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

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

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

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

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

Ответ 2

Первое, что мы должны иметь в виду, это то, что: 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 (Солнце).

Поэтому в Sun JVM соотношение живых объектов при каждой сборке мусора сохраняется в пределах 40-70%. Если после GC имеется менее 40% кучи, тогда куча расширяется. Поэтому, предполагая, что вы используете Sun JVM, я бы предположил, что размер "кучи java-объектов" достиг пика около 445 Мб, таким образом создавая расширенную "кучу объектов" около 740 Мб (чтобы гарантировать 40% бесплатную), Затем (куча объекта) + (вещественное пространство) = 740 + 250 = 990 Мб.

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

P.S.: при решении таких вопросов полезно размещать информацию о ОС и JVM.

Ответ 3

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

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

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

Если вам нужна дополнительная информация, прочитайте статью Tuning Garbage Collection Вот некоторые важные замечания из документа

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

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

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

Ответ 4

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

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

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