Native Memory Tracking.
С версии 1.8u40 в Oracle JDK включена возможность получать информацию о текущем использовании NativeMemory - Native Memory Tracking.Для включения NMT необходимо добавить ключ -XX:NativeMemoryTracking=detail
java -Xms450m -Xmx512m -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jarДля просмотра общей ниформации используется утилита jcmd с ключём summary
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory summary
Native Memory Tracking:Полный список "NMT Memory Categories" с их описанием можно посмотреть тут.
- Java Heap (reserved=524288KB, committed=460800KB)
(mmap: reserved=524288KB, committed=460800KB)
- Class (reserved=1072564KB, committed=26548KB)
(classes #3395)
(malloc=5556KB #2675)
(mmap: reserved=1067008KB, committed=20992KB)
- Thread (reserved=20648KB, committed=20648KB)
(thread #21)
(stack: reserved=20560KB, committed=20560KB)
(malloc=64KB #106)
(arena=23KB #40)
- Code (reserved=250784KB, committed=8012KB)
(malloc=1184KB #2669)
(mmap: reserved=249600KB, committed=6828KB)
- GC (reserved=24933KB, committed=24729KB)
(malloc=5773KB #176)
(mmap: reserved=19160KB, committed=18956KB)
- Compiler (reserved=150KB, committed=150KB)
(malloc=20KB #110)
(arena=131KB #3)
- Internal (reserved=5853KB, committed=5853KB)
(malloc=5821KB #4999)
(mmap: reserved=32KB, committed=32KB)
- Symbol (reserved=4901KB, committed=4901KB)
(malloc=2432KB #2557)
(arena=2469KB #1)
- Native Memory Tracking (reserved=362KB, committed=362KB)
(malloc=121KB #1921)
(tracking overhead=240KB)
- Arena Chunk (reserved=187KB, committed=187KB)
(malloc=187KB)
1. Java Heap
Область памяти в которой создаются объекты приложения.- Java Heap (reserved=524288KB, committed=460800KB)
(mmap: reserved=524288KB, committed=460800KB)
На примере, рассмотренном в предыдущем посте, описано, что ключ Xmx указывает количество памяти, выделяемое в виртуальном адресном пространстве процесса. Эта память никак не мапится на физическую память сервера.
-Xmx512m - reserved memory (reserved=524288KB)
ключ Xms указывает, какое количество памяти должно быть выделено (mmaped), но не обязательно использовано для heap-области процесса JVM на момент его старта. Эта память отображаться как Commited Memory. Если Xms меньше Xmx, то количество commited memory может увеличиваться по мере необходимости до порога, заданного значением reserved memory.
В примере -Xms450m - commited memory (committed=460800KB).
более подробную статистику по процессу можно посмотреть с помощью
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory detailСтатитстика, относящая к Heap представлена сразу после суммарной статистики
Virtual memory map:Под heap было выделено пространство [0x00000000e0000000 - 0x0000000100000000] reserved 524288KB
[0x00000000e0000000 - 0x0000000100000000] reserved 524288KB for Java Heap from
[0x00007f9986b73552] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0xc2
[0x00007f9986b73f2e] ReservedHeapSpace::ReservedHeapSpace(unsigned long, unsigned long, bool, char*)+0x6e
[0x00007f9986b40f2b] Universe::reserve_heap(unsigned long, unsigned long)+0x8b
[0x00007f99869f7474] ParallelScavengeHeap::initialize()+0x84
[0x00000000e0000000 - 0x00000000f2c00000] committed 307200KB from
[0x00007f9986a431e3] PSVirtualSpace::expand_by(unsigned long)+0x53
[0x00007f9986a332f7] PSOldGen::initialize(ReservedSpace, unsigned long, char const*, int)+0xb7
[0x00007f9986387cea] AdjoiningGenerations::AdjoiningGenerations(ReservedSpace, GenerationSizer*, unsigned long)+0x39a
[0x00007f99869f75c6] ParallelScavengeHeap::initialize()+0x1d6
[0x00000000f5580000 - 0x00000000feb80000] committed 153600KB from
[0x00007f9986a431e3] PSVirtualSpace::expand_by(unsigned long)+0x53
[0x00007f9986a441a5] PSYoungGen::initialize_virtual_space(ReservedSpace, unsigned long)+0x75
[0x00007f9986a44b0e] PSYoungGen::initialize(ReservedSpace, unsigned long)+0x3e
[0x00007f9986387c95] AdjoiningGenerations::AdjoiningGenerations(ReservedSpace, GenerationSizer*, unsigned long)+0x345
В него включено
[0x00000000e0000000 - 0x00000000f2c00000] committed 307200KB - под Old Gen
[0x00000000f5580000 - 0x00000000feb80000] committed 153600KB - под Young Gen
С помощью команды
pmap -X <pid>пожно получить аналогичные данные
java -Xms450m -Xmx512m -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
Address Perm Offset Device Inode Size Rss Pss Referenced Anonymous ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
00400000 r-xp 00000000 00:26 315842 4 4 2 4 0 0 0 0 0 0 0 java
00600000 rw-p 00000000 00:26 315842 4 4 4 4 4 0 0 0 0 0 0 java
021eb000 rw-p 00000000 00:00 0 132 20 20 20 20 0 0 0 0 0 0 [heap]
e0000000 rw-p 00000000 00:00 0 307200 12 12 12 12 0 0 0 0 0 0
f2c00000 ---p 00000000 00:00 0 42496 0 0 0 0 0 0 0 0 0 0
f5580000 rw-p 00000000 00:00 0 153600 113832 113832 113832 113832 0 0 0 0 0 0
feb80000 ---p 00000000 00:00 0 20992 0 0 0 0 0 0 0 0 0 0
100000000 rw-p 00000000 00:00 0 2816 2768 2768 2768 2768 0 0 0 0 0 0
Диапазон адресов, отданных под heap выделен красным.
Текущие области памяти New и Old выделены синим. Атрибуты rw-p в столбце Per:
rw - возможна запись и чтение памяти (PROT_READ | PROT_WRITE аргументы были заданы при выделении этой области памяти)
p - память выделена как private
сочетание разрешение ---p означает, что память пока только заразервирована.
rw - возможна запись и чтение памяти (PROT_READ | PROT_WRITE аргументы были заданы при выделении этой области памяти)
p - память выделена как private
сочетание разрешение ---p означает, что память пока только заразервирована.
JVM non Heap (Native) memory.
Все остальные области памяти процесса JVM относятся к так называемой non-Heap memory. Эти области памяти выделяются в Native memory ОС. Максимальное количество Native памяти, которую может использовать JVM процесс не ограничено по умолчанию.
2. Class
Эта область памяти используется для хранения метаданных классов. Данная область памяти использует Native память ОС. Верхняя граница количества памяти, использующейся под class metadata задаётся ключём -XX:MaxMetaspaceSize.
- Class (reserved=1072564KB, committed=26548KB)
(classes #3395)
(malloc=5556KB #2675)
(mmap: reserved=1067008KB, committed=20992KB)
Вывод утилиты показывает, что Reserved память составляет 1 Gb, но она практически не используется. Такой объём reserved memory объясняется nем, что для JVM с размером Heap меньше 32 Гб используется дефолтное значение ключа -XX:+UseCompressedOops. В свою очередь, при использовании этого ключа дефолтное значение ключа -XX:CompressedClassSpaceSize=1G.
1072564KB только резервируется процессом и не обязательно будет использоваться. В выводе видно, что размер committed memory всего 26548KB
Более подробный вывод:
/opt/oracle/java/latest/bin/jcmd <pid> VM.native_memory detail
[0x0000000100000000 - 0x0000000140000000] reserved 1048576KB for Class fromПомимо размера выделенной commited и reserved memory можно обнаружить вызов выделения области сжатых указателей Metaspace::allocate_metaspace_compressed_klass_ptrs, который резервирует в область размером в гигабайт.
[0x00007fed5e22c552] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0xc2
[0x00007fed5e22c78b] ReservedSpace::ReservedSpace(unsigned long, unsigned long, bool, char*, unsigned long)+0x1b
[0x00007fed5e00d080] Metaspace::allocate_metaspace_compressed_klass_ptrs(char*, unsigned char*)+0x40
[0x00007fed5e00f55f] Metaspace::global_initialize()+0x4cf
[0x0000000100000000 - 0x00000001002c0000] committed 2816KB from
[0x00007fed5e22bfc9] VirtualSpace::expand_by(unsigned long, bool)+0x199
[0x00007fed5e00b4e6] VirtualSpaceList::expand_node_by(VirtualSpaceNode*, unsigned long, unsigned long)+0x76
[0x00007fed5e00e300] VirtualSpaceList::expand_by(unsigned long, unsigned long)+0xf0
[0x00007fed5e00e493] VirtualSpaceList::get_new_chunk(unsigned long, unsigned long, unsigned long)+0xb3
В документации такое поведение объясняется необходимостью содержать отдельную структуру в памяти, обеспечивающую хранение смещения 64 битных указателей классов для работы с 32 битными указателями JVM. Наличие этой области актуально только при значениях ключей -XX:+UseCompressedOops и -XX:+UseCompressedClassesPointers использующихся по умолчанию для Heap меньше 32Gb.
Размер области сжатых указателей звдаётся ключём -XX:CompressedClassSpaceSize
При его чрезмерном уменьшениии возможна ошибка java.lang.OutOfMemoryError: Compressed class space
При отключении использования сжатых указателей (не рекомендуется т.к. даёт большой overhead на использование памяти) ключём -XX:-UseCompressedOops вывод NMT будет следующим:
java -Xms450m -Xmx512m -XX:-UseCompressedOops -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
Ограничить область памяти Calss можно ключами -XX:MaxMetaspcaseSize и XX:CompressedClassSpaceSize
[0x00007fe6f9000000 - 0x00007fe708000000] reserved 245760KB for Code from
[0x00007fe70f3036e6] ReservedSpace::initialize(unsigned long, unsigned long, bool, char*, unsigned long, bool)+0x256
[0x00007fe70f303d4c] ReservedCodeSpace::ReservedCodeSpace(unsigned long, unsigned long, bool)+0x2c
[0x00007fe70ee5ae85] CodeHeap::reserve(unsigned long, unsigned long, unsigned long)+0xa5
[0x00007fe70ecbfeb0] CodeCache::initialize()+0x80
[0x00007fe6f9570000 - 0x00007fe6f95a0000] committed 192KB from
[0x00007fe70f302fc9] VirtualSpace::expand_by(unsigned long, bool)+0x199
[0x00007fe70ee5ac6c] CodeHeap::expand_by(unsigned long)+0x8c
[0x00007fe70ecc0200] CodeCache::allocate(int, bool)+0x60
[0x00007fe70f12c13c] nmethod::new_nmethod(methodHandle, int, int, CodeOffsets*, int, DebugInformationRecorder*, Dependencies*, CodeBuffer*, int, OopMapSet*,
3. Thread
Количество памяти, занимаемое стэками потоков. Размер стэка каждого потока задаётся ключём -Xss. Дефолтный размер стэка 1024 байт. Его можно посмотреть так:/opt/oracle/java/latest/bin/java -XX:+PrintFlagsFinal -version | grep ThreadStackSize
intx VMThreadStackSize = 1024 {pd product}На каждый поток выделяется стэк размером VMThreadStackSize.
В выводе NMT каждый стэк выглядит так:
[0x00007f7a90f84000 - 0x00007f7a91085000] reserved and committed 1028KB for Thread Stack fromМожно заметить, что размер стэка 1028KB, а не 1024КБ.
[0x00007f7adc64f884] JavaThread::run()+0x24
[0x00007f7adc500568] java_start(Thread*)+0x108
вывод pmap -X, соответствующий данному потоку показывает, что под него выделено 2 области памяти 12Кб и 1016 Кб.
Address Perm Offset Device Inode Size Rss Pss Referenced Anonymous ShmemPmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked Mapping
7f7a47be2000 ---p 00000000 00:00 0 12 0 0 0 0 0 0 0 0 0 0
7f7a47be5000 rw-p 00000000 00:00 0 1016 88 88 88 88 0 0 0 0 0 0
Суммарная статистика показывает, что все стэки занимают 20648KB, что соответствует (20648-64-23)/1028=20 потокам.
- Thread (reserved=20648KB, committed=20648KB)
(thread #21)
(stack: reserved=20560KB, committed=20560KB)
(malloc=64KB #106)
(arena=23KB #40)
4. Code
В процессе работы процесс JVM выполняет некоторый байт-код. JVM может решить, что какой-то кусок кода выполняется достаточно часто и скомпилировать его в native-код. Native-код выполняется значительно быстрее и требует меньше ресурсов чем byte code. Для хранения скомпилированного кода используется native code cache. Размеры этой области задаются ключами-XX:ReservedCodeCacheSize - максимальное значение
-XX:InitialCodeCacheSize - размер области, выделяемый при старте.
Подбор ReservedCodeCacheSize значения происходит индивидуально для каждого приложения.
При компиляуии код проходит несколько степеней оптимизации.
level 0 - Интерпретатор JVM.
level 1 - C1 с оптимизацией, без профилирования
level 2 - C1 с учётом счётчиков количества обращений и "backedge"
level 3 - C1 с оптимизацией и профилированием
level 4 - C2
Для отключения компиляции в Native код используется ключ -Xint (не рекомендуется)
Для отключения промежуточных фаз компилирования и хранения только кода С2 можно использвать ключ -XX:-TieredCompilation. При этом критерием компиляции станнет значение CompileThreshold.
java -XX:+PrintFlagsFinal -version | grep CompileThreshold
intx CompileThreshold = 10000 {pd product}
intx Tier2CompileThreshold = 0 {product}
intx Tier3CompileThreshold = 2000 {product}
intx Tier4CompileThreshold = 15000 {product}
GC
Последняя относительно крупная область Native памяти JVM - память сборщика мусора. Она пропорциональна размеру Heap.Если JDK1.8 использует сборщик мусора G1, статистика использования памяти этим сборщиком будет примерно такая:
для Xms = 450M область GC составляет около 24Mb
- GC (reserved=24933KB, committed=24729KB)
(malloc=5773KB #176)
(mmap: reserved=19160KB, committed=18956KB)
для Xms = 2G область GC составляет около 80Mb
- GC (reserved=82395KB, committed=82395KB)
(malloc=5771KB #121)
(mmap: reserved=76624KB, committed=76624KB)
для Xms = 4G область GC составляет около 160Mb
(malloc=5771KB #121)
(mmap: reserved=153244KB, committed=153244KB)
То есть примерно 40 Mb на гигабайт Heap
Для CMS сборщика следует учитывать не только область GC, но и область Unлnown т.к. Native Memory Tracker не умеет (и, наверное, уже никогда не научится) правильно идентифицировать области памяти, использующиеся этим сборщиком.
java +UseConcMarkSweepGC -XX:NativeMemoryTracking=detail -jar /opt/gcviewer/gcviewer-1.35-SNAPSHOT.jar
для Xms = 2G область GC составляет примерно 16+60 = 76Mb
- GC (reserved=16891KB, committed=16891KB)
(malloc=9359KB #144)
(mmap: reserved=7532KB, committed=7532KB)
- Unknown (reserved=60648KB, committed=60648KB)
(mmap: reserved=60648KB, committed=60648KB)
для Xms = 4G область GC составляет примерно 25+93 = 120Mb
- GC (reserved=25083KB, committed=25083KB)
(malloc=9359KB #144)
(mmap: reserved=15724KB, committed=15724KB)
(mmap: reserved=93928KB, committed=93928KB)
Особенности окружения
Для glibc 2.12 и 2.17 существует особенность выделения памяти областями по 64 Mb. Данные версии библиотеки используется в Red Hat Enterprise Linux 6 и Red Hat Enterprise Linux 7. Я использую Fedora release 25 (Twenty Five) c версией пакета glibc-2.24-6.fc25.x86_64, где подобного поведения не наблюдается. При попытках повторить мои действия на ОС RHEL6/7 результаты теоретически должны сильно отличаться от результатов в Fedora 25. Несколько сократить фрагментацию должны помочь ключи:-XX:CodeCacheExpansionSize=1M -XX:CodeCacheMinimumFreeSpace=1M
-XX:MinMetaspaceExpansion=1M -XX:MaxMetaspaceExpansion=8M
Комментариев нет:
Отправить комментарий