Назад | Перейти на главную страницу

Разница между объемом памяти приложения JVM и памятью ОС

Я знаю, что этот вопрос уже обсуждался, но я не мог найти способ обрести душевное спокойствие.

В основном у нас есть веб-приложение java, которое работает под сервером приложений tomcat, а именно:

Нашему приложению требуется слишком много памяти, поэтому мы начинаем профилировать его; но я не могу понять простую разницу, которую я вижу между потреблением памяти приложения (куча / не куча) и памятью в ОС:

Профилировщик Yourkit:

Здесь память составляет 4,1 ГБ (выделенная куча) плюс 660 МБ (без кучи, поэтому Metaspace, кеш кода, сжатое пространство классов), поэтому 4,7 Гб всего

Память Windows:

Вот я вижу 6.266 Гб памяти, активно используемой процессом Tomcat

Как я могу измерить эту разницу в 1,5 Гб?

Это только для самого приложения Tomcat? Среда выполнения JVM? Если да, то как я могу это измерить?

редактировать: эта разница, кажется, увеличивается со временем после запуска сервера приложений (Tomcat); первоначально сумма Heap / Non Heap довольно близка к памяти, используемой процессом Tomcat, как записано ОС, затем через несколько часов / дней имеет тенденцию к увеличению.

Редактировать 2: наши параметры JAVA на сервере Tomcat

-Xms512m
-Xmx6144m
-Dlog=production
-DLog4jContextSelector=org.apache.logging.log4j.core.async.AsyncLoggerContextSelector
-Djava.util.Arrays.useLegacyMergeSort=true
-Duser.country=IT
-Duser.language=it
-XX:+UseG1GC
-XX:+UseStringDeduplication

Спасибо

Выделенная куча Java и рабочий набор Windows - это не одно и то же.

Разница в 1,5 ГБ связана с тем, как память обращается в Windows. Чтобы объяснить это, вот факты, которые я считаю наиболее важными:

  • xmx - 6 ГБ
  • Вы в Windows
  • «Лимит» на вашем графике составляет 5,3 ГБ.
  • Вы увидите это только после того, как сервер проработает несколько дней.

В Windows JVM требуется непрерывный блок виртуальной памяти для кучи. Он будет адресовать 6 ГБ при запуске приложения, но физически выделяет только то значение, которое вы изначально установили для 'xms'. Когда ваше приложение запускается, оно в конечном итоге выделяет для кучи больше памяти до 6 ГБ за вычетом всего, что вам нужно для памяти без кучи (например, Metaspace для Java 8+). Память без кучи должна оставаться практически постоянной на уровне 660 МБ, и, кроме того, может быть некоторая дополнительная память для самой JVM (128 МБ, я думаю?).

Ваша диаграмма из профиля показывает, что в настоящее время выделено 4,1 ГБ, но есть ограничение в 5,3 ГБ. Я считаю, что «предел» - это максимальный объем пространства, доступного для кучи, и он должен быть эквивалентен значению «xmx» за вычетом метапространства. Очень возможно, что 100% этого предельного значения будут сообщены как зафиксированные в операционной системе из-за требования иметь непрерывный блок памяти для кучи Java.

5,3 ГБ + 660 МБ = 5960+ МБ (возможно, больше, в зависимости от того, как округляли лимит). Если мы предположим, что это фактически добавляет к вашему значению xmx 6144, то 128 МБ для JVM = 6272 МБ, что немного больше, чем ваши 6266 МБ, которые Windows считает частными.

Единственный вопрос, который остается, - почему ваша JVM физически обратилась ко всей доступной куче, если для xms установлено значение 512 МБ? Ответ заключается в том, что он думал, что по какой-то причине потребуется физическая адресация всей кучи. Ясно, что в то время, когда вы его профилируете, это явно не так, но это довольно большой провал в вашем графике, когда он выполняет сборку мусора (например, 1 ГБ, выпущенный за один раз?) Стандартные ответы на это:

  • У вас может быть утечка памяти - этот график выглядит подозрительно
  • Возможно, JVM потребовалось больше оперативной памяти по какой-то совершенно веской причине, о которой вы не знаете (например, большая нагрузка).

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