Онлайн-настройка JVM
поиск проблемы
Обнаружено, что память приложения медленно и непрерывно увеличивается, и система предупреждает, что использование памяти системы превысило 80% и продолжает увеличиваться.
В частности, растет ВИЭ.
Вы можете проверить состояние памяти на целевом хосте с помощью следующей команды:
ps -p 1 -o pcpu,rss,size,vsize
RSS — это размер резидентного набора, который указывает размер памяти, выделенной процессу.
РАЗМЕР: адресное пространство, используемое процессом.Если процесс отображает 100 МБ памяти, адресное пространство процесса будет указано как 100 МБ памяти. На самом деле этот размер не является объемом памяти, который реально использует программа.
VSZ представляет виртуальную память, выделенную процессом. Включает всю память, к которой может получить доступ процесс, в том числе то, что идет в раздел подкачки, и память, занятую разделяемыми библиотеками.
анализ проблемы
Анализ внешнего вида подозревает, что это может быть утечка памяти, а поскольку память растет медленно и не продолжает быстро расти, склонен подозревать, что это не утечка памяти кучи.
Судя по данным мониторинга, соотношение памяти кучи и не кучи не очень велико. Итак, войдите в контейнер, чтобы просмотреть память java-процесса.
Мы используем версию JDK AdoptOpenJDK 11.0.8, не официальную версию JDK от oracle, а версию openJDK сообщества.
Само собой разумеется, что GC по умолчанию с java9 - это G1, но когда я смотрю на производственный jdk, он выглядит так:
java -XX:+PrintCommandLineFlags
-XX:InitialHeapSize=41943040 -XX:MaxHeapSize=671088640 -XX:+PrintCommandLineFlags -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseSerialGC
На самом деле с помощью SerialGC
Невероятно, поэтому я подумал о том, чтобы посмотреть параметры GC в процессе Java:
jhsdb jmap --heap --pid 1
Attaching to process ID 1, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 11.0.8+10
using thread-local object allocation.
Mark Sweep Compact GC
Это было подтверждено. Mark Sweep Compact GC, Mark - Clean - Алгоритм сжатия. Алгоритм Serial GC (-xx: + usserialgc), используемый в старческом.
решать
Если честно, я всегда думал, что наш jdk до этой версии является сборщиком мусора G1 по умолчанию, никакой конфигурации тоже нет. Но факт на лицо, я так посмотрел память выделенную под 2G, то на самом деле есть проблема.
Вопрос в том, какой GC использовать.Это не значит, что JDK9 и выше безмозглые, чтобы выбрать G1.
Вышеизложенное взято из третьего издания «Углубленное понимание виртуальной машины Java». Автор: Чжоу Чжимин.
Согласно нашей реальной ситуации, памяти около 2G, и мой выбор больше склоняется к использованию CMS.
Окончательные скорректированные параметры параметров jvm выглядят следующим образом:
-Xms2048m -Xmx2048m
-XX:+HeapDumpOnOutOfMemoryError
-XX:+CrashOnOutOfMemoryError
-XX:NativeMemoryTracking=detail
-XX:+UseConcMarkSweepGC
-XX:MetaspaceSize=256M
-XX:MaxMetaspaceSize=256M
-XX:ReservedCodeCacheSize=128m
-XX:InitialCodeCacheSize=128m
-Xss512k
-XX:+AlwaysPreTouch
Прежде чем объяснять некоторые важные параметры, сначала проанализируйте состав памяти приложения Java:
Total memory = Heap + Code Cache + Metaspace + Symbol tables +
Other JVM structures + Thread stacks +
Direct buffers + Mapped files +
Native Libraries + Malloc overhead + ...
Видно, что он грубо делится на две части: куча и не куча.
Вы также можете просмотреть память конкретного java-процесса с помощью команды:
jcmd 1 VM.native_memory
Отображаются похожие результаты:
Native Memory Tracking:
Total: reserved=1847158KB, committed=1561194KB
- Java Heap (reserved=1048576KB, committed=1048576KB)
(mmap: reserved=1048576KB, committed=1048576KB)
- Class (reserved=405345KB, committed=170849KB)
(classes #28273)
( instance classes #26587, array classes #1686)
(malloc=8033KB #97026)
(mmap: reserved=397312KB, committed=162816KB)
( Metadata: )
( reserved=143360KB, committed=142336KB)
( used=138699KB)
( free=3638KB)
( waste=0KB =0.00%)
( Class space:)
( reserved=253952KB, committed=20480KB)
( used=18340KB)
( free=2140KB)
( waste=0KB =0.00%)
- Thread (reserved=68673KB, committed=17205KB)
(thread #126)
(stack: reserved=68072KB, committed=16604KB)
(malloc=454KB #758)
(arena=147KB #251)
- Code (reserved=136634KB, committed=136634KB)
(malloc=4538KB #15693)
(mmap: reserved=132096KB, committed=132096KB)
- GC (reserved=7511KB, committed=7511KB)
(malloc=3575KB #5347)
(mmap: reserved=3936KB, committed=3936KB)
- Compiler (reserved=1027KB, committed=1027KB)
(malloc=894KB #1383)
(arena=133KB #5)
- Internal (reserved=18773KB, committed=18773KB)
(malloc=18741KB #7974)
(mmap: reserved=32KB, committed=32KB)
- Other (reserved=66199KB, committed=66199KB)
(malloc=66199KB #85)
- Symbol (reserved=32192KB, committed=32192KB)
(malloc=28412KB #365132)
(arena=3780KB #1)
- Native Memory Tracking (reserved=8657KB, committed=8657KB)
(malloc=544KB #7707)
(tracking overhead=8112KB)
- Arena Chunk (reserved=2036KB, committed=2036KB)
(malloc=2036KB)
- Logging (reserved=4KB, committed=4KB)
(malloc=4KB #191)
- Arguments (reserved=18KB, committed=18KB)
(malloc=18KB #495)
- Module (reserved=2706KB, committed=2706KB)
(malloc=2706KB #10716)
- Synchronizer (reserved=738KB, committed=738KB)
(malloc=738KB #6245)
- Safepoint (reserved=8KB, committed=8KB)
(mmap: reserved=8KB, committed=8KB)
- Unknown (reserved=48060KB, committed=48060KB)
(mmap: reserved=48060KB, committed=48060KB)
-XX:NativeMemoryTracking=detail
Причина приведенных выше результатов отображения заключается в том, что я добавил этот параметр
-XX:MetaspaceSize
Специфично для моей конфигурации, почему я должен установить его-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M
,Как показано ниже:
- Если указано -XX: + UseCompressedOops и -XX: + UseCompressedClassesPointers (включено по умолчанию), то UseCompressedOops использует 32-битное смещение для представления ссылки на объект Java, а 32-битное смещение UseCompressedClassPointers используется для представления 64-битного класса процесса. указатель; CompressedClassSpaceSize можно использовать для установки размера этого пространства
- Если сжатие повернутого указателя разделено внутри MaxMetaspaceSize CompressedClassSpace, т. е. MaxMetaspaceSize = размер пространства сжатого класса + размер области метапространства (исключая пространство сжатого класса)
Поэтому мы фиксируем размер пространства сжатого класса в метапространстве, потому что по умолчанию1G
-Xss512k
Размер стека контролируется параметром -Xss. По умолчанию 1M на поток, скорректировано до 512K.
-XX:+AlwaysPreTouch
Во-первых, давайте кратко рассмотрим.Хотя размер кучи JVM может быть установлен с помощью параметров -Xmx и -Xms JVM, операционная система в это время выделяет только виртуальную память.Физическая память будет выделяться только тогда, когда JVM очень хочет использовать память.
Сначала объекты будут выделены в молодого поколения, потому что раньше выделяется только виртуальная память, поэтому каждый раз, когда создается новый объект, операционная система должна сначала распределить физическую память, а скорость выделения объектов, естественно, уменьшится. Только после Первое GC новое поколение, выделенное выделенное пространство памяти было выделено, а затем скорость выделения объектов будет ускорена.
Это также та же самая причина старости, старости, когда пространство фактически используется естественным образом, когда объекты должны быть переведены в старую эпоху, поэтому GC нового поколения при переходе к новому поколению объектов из старой эпохи, операционная система также должна лет выделяют физическую память, таким образом косвенно влияя на эффективность GC нового поколения.
Эффект, который может быть достигнут с помощью параметра [-xx: + AlwaysPreTouch],При старте сервиса под JVM фактически выделяется физическая память, а не виртуальная.Эффект заключается в ускорении эффективности кода.Есть и некоторые минусы.Ведь выделение физической памяти делается заранее при запуске процесса JVM Это, естественно, влияет на время запуска процесса JVM, что приводит к сокращению времени запуска на порядки.
-XX:ReservedCodeCacheSize
- -XX:ReservedCodeCacheSize=128m
- -XX:InitialCodeCacheSize=128m
Кэш кода это так называемый кеш кода.Поскольку память виртуальной машины JVM по умолчанию имеет ограничение на размер, то и область кеша кода должна иметь определенный размер.Значение по умолчанию 240М.Значение моих настроек параметра на основе данных мониторинга работы системы.Вывод, если вы хотите установить, пожалуйста, устанавливайте в соответствии с реальной ситуацией, не строчите.
С другой стороны, если код cacahe заполнен, оставьте его в покое, вы можете настроить очистку
-XX:+UseCodeCacheFlushing
Если пространство кэша кода заполнено, включите его, добавив: -XX:+UseCodeCacheFlushing к параметру запуска. Когда эта опция включена, перед закрытием JIT, то есть до того, как CodeCache будет заполнен, будет выполнена очистка перед закрытием JIT, и некоторые коды CodeCache будут удалены; если после очистки еще нет места , JIT по-прежнему будет закрыт.
这个选项默认是关闭的
окончание
Когда я заменил G1 на CMS, раскладка и размер памяти были сброшены согласно моим настройкам. Рост памяти имеет тенденцию, но особенно медленный и с циклическим ритмом.
Я также сделал дамп снимков памяти, и у меня есть подозрение на утечку памяти, вызванную использованием JNI внутри артаса, но прямых доказательств не обнаружено.В настоящее время я все еще сначала наблюдаю, и продолжаю анализировать по ситуации после наблюдения за определенный период.