JVM本地内存的使用监控情况
JVM本地内存的使用监控情况
文章目录
- JVM本地内存的使用监控情况
- NMT跟踪的内存
- 使用 NMT 检测内存泄漏
- 如何监控虚拟机内部内存
- 获取摘要报告
- 查询详细报告
- 查询跟踪变化报告
NMT,全称为Native Memory Tracking,是Java 8u40版本引入的一项功能,用于跟踪JVM本身在本地内存中的内存使用情况。
NMT 不支持跟踪非 JVM 代码的内存分配,需要使用操作系统支持的工具来检测本地代码中的内存泄漏。
启用 NMT 会导致 JVM 性能下降 5%~10%,并且NMT的内存使用将在所有malloc内存中添加2个机器字作为malloc头。
NMT跟踪的内存
本机内存跟踪内存类别
类别 | 说明 |
---|---|
Java Heap | The heap where your objects live 对象所在的堆的内存使用情况 |
Class | Class meta data 元数据区使用的内存情况 |
Code | Generated code JIT产生的汇编指令所占的空间情况 |
GC | data use by the GC, such as card table 由GC使用的内存情况,如card table |
Compiler | Memory used by the compiler when generating code 编译器在生成代码时使用的内存情况 |
Symbol | Symbols 符号,如同String table和常量池 |
Memory Tracking | Memory used by NMT itself NMT本身使用的内存 |
Pooled Free Chunks | Memory used by chunks in the arena chunk pool chunks 池中块使用的内存 |
Shared space for classes | Memory mapped to class data sharing archive 内存映射到类数据共享归档 |
Thread | Memory used by threads, including thread data structure, resource area and handle area and so on. 线程使用的内存,包括线程数据结构、资源区和句柄区等。 |
Thread stack | Thread stack. It is marked as committed memory, but it might not be completely committed by the OS 线程栈。 它被标记为已提交内存,但操作系统可能不会完全提交它 |
Internal | Memory that does not fit the previous categories, such as the memory used by the command line parser, JVMTI, properties and so on. 不属于前几类的内存,如命令行解析器、JVMTI、属性等使用的内存。 |
Unknown | When memory category can not be determined.Arena: When arena is used as a stack or value objectVirtual Memory: When type information has not yet arrived 当无法确定内存类别时: 当arena 被用作堆栈或值对象时虚拟内存: 当类型信息尚未统计到时 |
使用 NMT 检测内存泄漏
-
启动Java程序时,需要增加下列命令行选项:
-XX:NativeMemoryTracking=summary
或-XX:NativeMemoryTracking=detail
,以summary或detail跟踪方式启动 JVM。 -
建立早期基线–使用 NMT base功能获得基线,以便在开发和维护期间进行比较,方法是运行:
jcmd <pid> VM.native_memory baseline
-
使用下面命令, 监控内存变化:
jcmd <pid> VM.native_memory detail.diff
-
如果应用程序泄漏了少量内存,则需要运行一段时间才能显示出来。
如何监控虚拟机内部内存
Arena 是使用 malloc 分配的一大块内存。在退出作用域或离开代码区域时,会从这些内存块中批量释放内存。这些内存块可在其他子系统中重复使用,以保存临时内存,例如线程前分配。Arena 的 malloc 策略可确保无内存泄漏。因此,Arena 将作为一个整体而非单个对象进行跟踪。有些初始内存是无法跟踪的。
与 jcmd
实用程序一起使用时,可以查询空间情况。
下文将介绍如何获取 NMT 的摘要或详细数据,以及如何解释示例输出。
获取摘要报告
前提:使用命令行选项 -XX:NativeMemoryTracking=summary
启动 JVM。
使用命令:
jcmd <pid> VM.native_memory summary
结果示例:
Total: reserved=664192KB, committed=253120KB <--- total memory tracked by Native Memory Tracking- Java Heap (reserved=516096KB, committed=204800KB) <--- Java Heap(mmap: reserved=516096KB, committed=204800KB)- Class (reserved=6568KB, committed=4140KB) <--- class metadata(classes #665) <--- number of loaded classes(malloc=424KB, #1000) <--- malloc'd memory, #number of malloc(mmap: reserved=6144KB, committed=3716KB)- Thread (reserved=6868KB, committed=6868KB)(thread #15) <--- number of threads(stack: reserved=6780KB, committed=6780KB) <--- memory used by thread stacks(malloc=27KB, #66)(arena=61KB, #30) <--- resource and handle areas- Code (reserved=102414KB, committed=6314KB)(malloc=2574KB, #74316)(mmap: reserved=99840KB, committed=3740KB)- GC (reserved=26154KB, committed=24938KB)(malloc=486KB, #110)(mmap: reserved=25668KB, committed=24452KB)- Compiler (reserved=106KB, committed=106KB)(malloc=7KB, #90)(arena=99KB, #3)- Internal (reserved=586KB, committed=554KB)(malloc=554KB, #1677)(mmap: reserved=32KB, committed=0KB)- Symbol (reserved=906KB, committed=906KB)(malloc=514KB, #2736)(arena=392KB, #1)- Memory Tracking (reserved=3184KB, committed=3184KB)(malloc=3184KB, #300)- Pooled Free Chunks (reserved=1276KB, committed=1276KB)(malloc=1276KB)- Unknown (reserved=33KB, committed=33KB)(arena=33KB, #1)
查询详细报告
前提:使用命令行选项 -XX:NativeMemoryTracking=detail
启动 JVM。
使用命令:
jcmd <pid> VM.native_memory detail
结果示例:
Virtual memory map:[0x8f1c1000 - 0x8f467000] reserved 2712KB for Thread Stackfrom [Thread::record_stack_base_and_size()+0xca][0x8f1c1000 - 0x8f467000] committed 2712KB from [Thread::record_stack_base_and_size()+0xca][0x8f585000 - 0x8f729000] reserved 1680KB for Thread Stackfrom [Thread::record_stack_base_and_size()+0xca][0x8f585000 - 0x8f729000] committed 1680KB from [Thread::record_stack_base_and_size()+0xca][0x8f930000 - 0x90100000] reserved 8000KB for GCfrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555][0x8f930000 - 0x90100000] committed 8000KB from [PSVirtualSpace::expand_by(unsigned int)+0x95][0x902dd000 - 0x9127d000] reserved 16000KB for GCfrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555][0x902dd000 - 0x9127d000] committed 16000KB from [os::pd_commit_memory(char*, unsigned int, unsigned int, bool)+0x36][0x9127d000 - 0x91400000] reserved 1548KB for Thread Stackfrom [Thread::record_stack_base_and_size()+0xca][0x9127d000 - 0x91400000] committed 1548KB from [Thread::record_stack_base_and_size()+0xca][0x91400000 - 0xb0c00000] reserved 516096KB for Java Heap <--- reserved memory rangefrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x190] <--- callsite that reserves the memory[0x91400000 - 0x93400000] committed 32768KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x3e8] <--- committed memory range and its callsite[0xa6400000 - 0xb0c00000] committed 172032KB from [PSVirtualSpace::expand_by(unsigned int)+0x95] <--- committed memory range and its callsite[0xb0c61000 - 0xb0ce2000] reserved 516KB for Thread Stackfrom [Thread::record_stack_base_and_size()+0xca][0xb0c61000 - 0xb0ce2000] committed 516KB from [Thread::record_stack_base_and_size()+0xca][0xb0ce2000 - 0xb0e83000] reserved 1668KB for GCfrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555][0xb0ce2000 - 0xb0cf0000] committed 56KB from [PSVirtualSpace::expand_by(unsigned int)+0x95][0xb0d88000 - 0xb0d96000] committed 56KB from [CardTableModRefBS::resize_covered_region(MemRegion)+0xebf][0xb0e2e000 - 0xb0e83000] committed 340KB from [CardTableModRefBS::resize_covered_region(MemRegion)+0xebf][0xb0e83000 - 0xb7003000] reserved 99840KB for Codefrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555][0xb0e83000 - 0xb0e92000] committed 60KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x3e8][0xb1003000 - 0xb139b000] committed 3680KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x37a][0xb7003000 - 0xb7603000] reserved 6144KB for Classfrom [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555][0xb7003000 - 0xb73a4000] committed 3716KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x37a][0xb7603000 - 0xb760b000] reserved 32KB for Internalfrom [PerfMemory::create_memory_region(unsigned int)+0x8ba][0xb770b000 - 0xb775c000] reserved 324KB for Thread Stackfrom [Thread::record_stack_base_and_size()+0xca][0xb770b000 - 0xb775c000] committed 324KB from [Thread::record_stack_base_and_size()+0xca]
查询跟踪变化报告
对于summary和detail级别的跟踪,可以在应用程序启动并运行后设置基线。设置baseline命令:
jcmd <pid> VM.native_memory baseline
查询不同级别变化报告命令
jcmd <pid> VM.native_memory summary.diffjcmd <pid> VM.native_memory detail.diff
命令可以带上单位
jcmd <pid> VM.native_memory summary.diff scale=MB
summary级别变化报告结果示例
Total: reserved=664624KB -20610KB, committed=254344KB -20610KB <--- total memory changes vs. earlier baseline. '+'=increase '-'=decrease- Java Heap (reserved=516096KB, committed=204800KB)(mmap: reserved=516096KB, committed=204800KB)- Class (reserved=6578KB +3KB, committed=4530KB +3KB)(classes #668 +3) <--- 3 more classes loaded(malloc=434KB +3KB, #930 -7) <--- malloc'd memory increased by 3KB, but number of malloc count decreased by 7(mmap: reserved=6144KB, committed=4096KB)- Thread (reserved=60KB -1129KB, committed=60KB -1129KB)(thread #16 +1) <--- one more thread(stack: reserved=7104KB +324KB, committed=7104KB +324KB)(malloc=29KB +2KB, #70 +4)(arena=31KB -1131KB, #32 +2) <--- 2 more arenas (one more resource area and one more handle area)- Code (reserved=102328KB +133KB, committed=6640KB +133KB)(malloc=2488KB +133KB, #72694 +4287)(mmap: reserved=99840KB, committed=4152KB)- GC (reserved=26154KB, committed=24938KB)(malloc=486KB, #110)(mmap: reserved=25668KB, committed=24452KB)- Compiler (reserved=106KB, committed=106KB)(malloc=7KB, #93)(arena=99KB, #3)- Internal (reserved=590KB +35KB, committed=558KB +35KB)(malloc=558KB +35KB, #1699 +20)(mmap: reserved=32KB, committed=0KB)- Symbol (reserved=911KB +5KB, committed=911KB +5KB)(malloc=519KB +5KB, #2921 +180)(arena=392KB, #1)- Memory Tracking (reserved=2073KB -887KB, committed=2073KB -887KB)(malloc=2073KB -887KB, #84 -210)- Pooled Free Chunks (reserved=2624KB -15876KB, committed=2624KB -15876KB)(malloc=2624KB -15876KB)
Details级别变化报告结果示例
Details:[0x01195652] ChunkPool::allocate(unsigned int)+0xe2(malloc=482KB -481KB, #8 -8)[0x01195652] ChunkPool::allocate(unsigned int)+0xe2(malloc=2786KB -19742KB, #134 -618)[0x013bd432] CodeBlob::set_oop_maps(OopMapSet*)+0xa2(malloc=591KB +6KB, #681 +37)[0x013c12b1] CodeBuffer::block_comment(int, char const*)+0x21 <--- [callsite address] method name + offset(malloc=562KB +33KB, #35940 +2125) <--- malloc'd amount, increased by 33KB #malloc count, increased by 2125[0x0145f172] ConstantPool::ConstantPool(Array<unsigned char>*)+0x62(malloc=69KB +2KB, #610 +15)...[0x01aa3ee2] Thread::allocate(unsigned int, bool, unsigned short)+0x122(malloc=21KB +2KB, #13 +1)[0x01aa73ca] Thread::record_stack_base_and_size()+0xca(mmap: reserved=7104KB +324KB, committed=7104KB +324KB)