Я знаю, что этот вопрос уже обсуждался, но я не мог найти способ обрести душевное спокойствие.
В основном у нас есть веб-приложение 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. Чтобы объяснить это, вот факты, которые я считаю наиболее важными:
В 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 физически выделяет оперативную память, она редко возвращает ее. Может, и с G1GC он должен делать это чаще, чем с другими сборщиками мусора, но вы не должны предполагать, что рабочий набор, который видит операционная система, действительно выйдет из строя.