#java #tomcat #memory #jvm
#java #tomcat #память #jvm
Вопрос:
Я наблюдаю несоответствие в потреблении оперативной памяти Tomcat между тем, что говорит ОС, и тем, что говорит jVisualVM.
Начиная с htop, Tomcat JVM имеет 993 МБ резидентной памяти
Из jVisualVM JVM Tomcat использует
- Максимальная куча: 1 070 399 488 Б
- Размер кучи: 298.438.656 B
- Используемая куча: переменная, от 170 МБ до и 270 МБ
- Максимальный постоянный объем: 268,435,456 Б
- Постоянный размер: 248 872 960 Б
- Используемый PermGen: слегка изменяющийся, около 150 МБ
Насколько я понимаю, потребление памяти ОС должно составлять размер кучи постоянный размер ~ = 522 МБ. Но это на 471 МБ меньше, чем я наблюдаю.
У кого-нибудь есть идея, чего мне здесь не хватает?
PS: Я знаю, что моя максимальная куча намного выше, чем используемая, но я предполагаю, что это не должно иметь никакого эффекта, если JVM ее не использует (т. Е. Размер кучи меньше).
Спасибо! Марк
Комментарии:
1. включает ли ваш номер кучи как старое поколение, так и молодое поколение?
2. В вашем сообщении вы дважды упомянули «Размер PermGem»: «Размер PermGen: 248 872 960 B, размер PermGen: слегка варьируется, около 150 МБ». Это нормально?
3. 1 Я тоже хотел бы это понять. Я получаю некоторую ошибку нехватки памяти для pergem, поэтому будет полезно дать мне некоторое представление о том, что происходит.
4. @Kevin Я предполагаю, что это как старое поколение, так и молодое поколение
Ответ №1:
Насколько я понимаю, потребление памяти ОС должно составлять размер кучи постоянный размер ~ = 522 МБ. Но это на 471 МБ меньше, чем я наблюдаю. У кого-нибудь есть идея, чего мне здесь не хватает?
Если я понимаю вопрос, который вы видите, это комбинация фрагментации памяти и накладных расходов памяти JVM в других областях. Мы часто видим в 2 раза больше использования памяти для наших производственных программ, чем мы ожидаем увидеть из наших настроек памяти.
Фрагментация памяти может означать, что, хотя JVM считает, что ОС предоставила ей некоторое количество байтов, существует определенное дополнительное количество байтов, которое необходимо было предоставить из-за оптимизации подсистемы памяти.
Что касается служебных данных JVM, существует ряд других областей хранения, которые не включены в стандартные конфигурации памяти. Вот хорошая дискуссия об этом. Цитировать:
Ниже приведены примеры вещей, которые не являются частью кучи сбора мусора, но все же являются частью памяти, требуемой процессом:
- Код для реализации JVM
- Ручная куча C для структур данных, реализующих JVM
- Стеки для всех потоков в системе (приложение JVM)
- Кэшированный байт-код Java (для библиотек и приложения)
- JITed машинный код (для библиотек и приложения)
- Статические переменные всех загруженных классов
Комментарии:
1. Все ответы дали хорошие подсказки, но оказалось, что на этот приходится большая часть дополнительной памяти. Одним из моментов является то, что XMX будет резервировать виртуальную память на уровне ОС, но это не считается «выделенной» или «резидентной» памятью (которая устанавливается XMS). Другой момент заключается в том, что с помощью jconsole я могу учитывать больше памяти «без кучи» (около 20 МБ). И, наконец, остальная часть памяти, похоже, используется самой JVM, как описано выше.
Ответ №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).
Следовательно, в Sun JVM соотношение живых объектов при каждой сборке мусора поддерживается в пределах 40-70%. Если после GC освобождается менее 40% кучи, то куча расширяется. Итак, предполагая, что вы используете Sun JVM, я бы предположил, что размер «кучи объектов Java» достиг пика около 445 МБ, что приводит к увеличению «кучи объектов» примерно на 740 Мб (чтобы гарантировать 40% свободного места). Тогда (куча объектов) (постоянное пространство) = 740 250 = 990 Мб.
Возможно, вы можете попытаться вывести данные GC или использовать jconsole для проверки изменения размера кучи.
PS: при решении подобных проблем полезно публиковать сведения об ОС и JVM.
Комментарии:
1. Я только что настроил сегодня JVM и заметил, что при Xms == Xmx = 3000m полное распределение оперативной памяти с точки зрения ОС составило около 8-10 ГБ… Я даже попадал в ситуации, когда я использовал Xmx = 7000, поскольку процесс занял почти всю доступную память 16 ГБ, а ядро остановило процесс 🙂 Обычно я видел, что если Xmx = 1g, то на уровне ОС max — максимум 1,5, но это другая история, в данный момент я этого не понимаю. Это вынуждает меня снизить Xmx на 2,5 x максимальной оперативной памяти с точки зрения ОС.
2. На самом деле, согласно одному из документов Oracle , они заявляют: например, JVM HotSpot, работающий в Linux, сконфигурированный с JVM объемом 1 ГБ, потребляет примерно 1,2 ГБ оперативной памяти
Ответ №3:
Во время запуска вашего приложения JVM будет резервировать память, примерно равную размеру вашего максимального значения кучи (-Xmx) плюс немного больше для других вещей. Это избавляет JVM от необходимости возвращаться к ОС, чтобы позже зарезервировать больше памяти.
Даже если ваше приложение использует только 298 МБ кучи, в ОС все равно будет зарезервировано 993 МБ. Вам нужно будет больше читать в зарезервированной или выделенной памяти.
Большинство статей, которые вы прочитаете, когда речь пойдет о сборке мусора, будут относиться к распределению с точки зрения кучи, а не уровня ОС. Резервируя память при запуске для вашего приложения, сборка мусора может работать в своем собственном пространстве.
Если вам нужна более подробная информация, прочитайте статью Настройка сборки мусора, вот некоторые важные выдержки из документа
При инициализации максимальное адресное пространство фактически резервируется, но не выделяется для физической памяти, если это не необходимо.
Также посмотрите раздел 3.2 (iv) в документе
При инициализации виртуальной машины все пространство для кучи зарезервировано. Размер зарезервированного пространства можно указать с помощью параметра -Xmx. Если значение параметра -Xms меньше значения параметра -Xmx, не все зарезервированное пространство немедленно передается виртуальной машине.
Ответ №4:
ОС сообщит о памяти, используемой JVM память, используемая вашей программой. Таким образом, оно всегда будет выше, чем то, что JVM сообщает как использование памяти. Для выполнения вашей программы самой JVM требуется определенный объем памяти, и ОС не может определить разницу.
К сожалению, использование инструментов системной памяти — не очень точный способ отслеживать потребление памяти вашими программами. JVM обычно выделяют большие блоки памяти, поэтому создание объекта происходит быстро, но это не означает, что ваша программа использует эту память.
Лучший способ узнать, что на самом деле делает ваша программа, — запустить jconsole и посмотреть на использование памяти там. Это очень простой инструмент для просмотра памяти, который легко настроить.