Java Native Memory Tracking 追踪 JVM 内存使用情况

NMT JVM Java About 8,639 words

开启 NMT

  • -XX:NativeMemoryTracking=off: NMT默认关闭,需在启动时开启。
  • -XX:NativeMemoryTracking=summary: 开启NMT
  • -XX:NativeMemoryTracking=detail: 开启NMT,比summary级别统计更详细,内存占用更多。

备注

文章中的1是进程ID

关闭 NMT

jcmd 1 VM.native_memory shutdown

使用 NMT

jcmd 1 VM.native_memory

对比

开启基线

jcmd 1 VM.native_memory baseline

查看差异

jcmd 1 VM.native_memory summary.diff

示例信息

bash-4.4$ jcmd 1 VM.native_memory
1:

Native Memory Tracking:

(Omitting categories weighting less than 1KB)

Total: reserved=1040798KB, committed=701478KB
       malloc: 42678KB #386484
       mmap:   reserved=998120KB, committed=658800KB

-                 Java Heap (reserved=512000KB, committed=512000KB)
                            (mmap: reserved=512000KB, committed=512000KB) 

-                     Class (reserved=83129KB, committed=8633KB)
                            (classes #13125)
                            (  instance classes #12273, array classes #852)
                            (malloc=1209KB #23704) 
                            (mmap: reserved=81920KB, committed=7424KB) 
                            (  Metadata:   )
                            (    reserved=65536KB, committed=49920KB)
                            (    used=49570KB)
                            (    waste=350KB =0.70%)
                            (  Class space:)
                            (    reserved=81920KB, committed=7424KB)
                            (    used=7059KB)
                            (    waste=365KB =4.92%)

-                    Thread (reserved=26869KB, committed=3541KB)
                            (thread #48)
                            (stack: reserved=26744KB, committed=3416KB)
                            (malloc=72KB #286) 
                            (arena=53KB #92)

-                      Code (reserved=249313KB, committed=23753KB)
                            (malloc=1625KB #7902) 
                            (mmap: reserved=247688KB, committed=22128KB) 

-                        GC (reserved=69379KB, committed=69379KB)
                            (malloc=17479KB #8391) 
                            (mmap: reserved=51900KB, committed=51900KB) 

-                 GCCardSet (reserved=140KB, committed=140KB)
                            (malloc=140KB #1735) 

-                  Compiler (reserved=340KB, committed=340KB)
                            (malloc=175KB #801) 
                            (arena=165KB #5)

-                  Internal (reserved=461KB, committed=461KB)
                            (malloc=457KB #11216) 
                            (mmap: reserved=4KB, committed=4KB) 

-                     Other (reserved=112KB, committed=112KB)
                            (malloc=112KB #21) 

-                    Symbol (reserved=12518KB, committed=12518KB)
                            (malloc=11295KB #311929) 
                            (arena=1223KB #1)

-    Native Memory Tracking (reserved=6331KB, committed=6331KB)
                            (malloc=292KB #4176) 
                            (tracking overhead=6039KB)

-        Shared class space (reserved=12288KB, committed=11968KB)
                            (mmap: reserved=12288KB, committed=11968KB) 

-               Arena Chunk (reserved=197KB, committed=197KB)
                            (malloc=197KB) 

-                   Tracing (reserved=32KB, committed=32KB)
                            (arena=32KB #1)

-                    Module (reserved=84KB, committed=84KB)
                            (malloc=84KB #1357) 

-                 Safepoint (reserved=8KB, committed=8KB)
                            (mmap: reserved=8KB, committed=8KB) 

-           Synchronization (reserved=137KB, committed=137KB)
                            (malloc=137KB #1475) 

-            Serviceability (reserved=17KB, committed=17KB)
                            (malloc=17KB #14) 

-                 Metaspace (reserved=65775KB, committed=50159KB)
                            (malloc=239KB #102) 
                            (mmap: reserved=65536KB, committed=49920KB) 

-      String Deduplication (reserved=1635KB, committed=1635KB)
                            (malloc=1635KB #13216) 

-                   Unknown (reserved=32KB, committed=32KB)
                            (mmap: reserved=32KB, committed=32KB)

显示单位为MB

bash-4.4$ jcmd 1 VM.native_memory summary scale=MB
1:

Native Memory Tracking:

Total: reserved=4817MB, committed=1139MB
-                 Java Heap (reserved=3288MB, committed=971MB)
                            (mmap: reserved=3288MB, committed=971MB) 

-                     Class (reserved=1066MB, committed=47MB)
                            (classes #10170)
                            (  instance classes #9495, array classes #675)
                            (malloc=2MB #27171) 
                            (mmap: reserved=1064MB, committed=45MB) 
                            (  Metadata:   )
                            (    reserved=40MB, committed=39MB)
                            (    used=37MB)
                            (    free=1MB)
                            (    waste=0MB =0.00%)
                            (  Class space:)
                            (    reserved=1024MB, committed=6MB)
                            (    used=5MB)
                            (    free=1MB)
                            (    waste=0MB =0.00%)

含义

Total

总的统计信息。

Java Heap

堆内存使用情况,堆内存通过mmap的方式申请。

基于节省内存资源还可以启用uncommit机制等。

通过设置-Xmx限制最大的堆内存占用。

通过设置-Xms限制最小的堆内存占用。

Class

类元数据使用的内存空间,加载的类与方法信息,即虚拟机规范中规定的方法区。

其实就是metaspace,包含两部分: 一是Metadata,另外是Class space

JVM C++层面的内存占用。

JDK8之后StringTable就被移入HeapNMTStringTable所使用的内存被单独统计到了Symbol中。

通过设置-XX:MaxMetaspaceSize限制Metadata所使用的内存大小。

通过设置-XX:CompressedClassSpaceSize限制Class space所使用的内存大小。

Thread

线程与线程栈占用内存。

aarch64平台下默认为2M

x86平台下默认为1M

通过设置-Xss/-XX:ThreadStackSize限制每个线程栈占用的内存,总大小没有限制。

Code

Code Cache存放native code,这些native code由动态生成的解释器循环、JNI、即时编译器(JIT)编译Java方法产生。

JIT生成的native code占用了Code Cache的绝大部分空间。

通过设置-XX:ReservedCodeCacheSize限制Code的最大内存。

GC

4)GC:垃圾回收占用内存,例如垃圾回收需要的 CardTable,标记数,区域划分记录,还有标记 GC Root 等等,都需要内存。这个不受限制,对于吞吐量优先的GC,例如 ParallelGC,不会很大,对于延迟优先的,例如 ZGC 会非常大(而且目前 ZGC 还是不分代,就更大了)。对于均衡型,例如 G1GC,可能会有几百兆 这个不受限制,一般不会很大,但也有例外,图3是27G的堆内存,使用G1垃圾回收器,你能看到GC区居然占用了3.8G的内存;

GCCardSet

只有G1GC才有这个分类,统计Remember Sets记忆集数据占用的大小。(Java 18开始NMT才从GC分类中独立出来统计)

Compiler

JIT编译器本身占用的空间,C1C2编译器本身的代码和标记占用的内存,不受限制,一般不会很大。

通过设置-XX:CICompilerCount指定编译线程的数量,限制Compiler部分所使用的内存(当然这部分内存比较小)。

编译线程也是线程,所以还可以通过-XX:CompilerThreadStackSize设置一个更小的值来节省此部分内存,但是削减虚拟机线程的堆栈大小是危险的操作,并不建议去因为此设置这个参数。

Internal

包含命令行解析器使用的内存、JVMTI(JVM Tool Interface)、PerfData以及Unsafe分配的内存等等。这个不受限制,一般不会很大的。

命令行解释器就是在初始化创建虚拟机时对 JVM 的命令行参数加以解析并执行相应的操作,如对参数-XX:NativeMemoryTracking=detail进行解析。

如果使用了像是Skywalking这种基于agent的,那么可能会很大,有几百兆。

Other

JVM内部不属于其他类的占用就会归到这一类,不是JVM本身而是操作系统的某些系统调用导致额外占的空间,一般不会很大的。

Symbol

字符串常量池占用的大小。

C++字符串占用空间(不是Java字符串)

-XX:StringTableSize并不是来限制StringTable最大申请的内存大小,而是用来限制StringTable的表的长度。

StringTableHotSpot中是以HashTable的形式存储的,所以-XX:StringTableSize参数设置的其实是HashTable的长度,如果该值设置的过小的话,即使HashTable进行rehashhash冲突也会十分频繁,会造成性能劣化并有可能导致进入SafePoint 的时间增长。

总内存大小不受限制。

Native Memory Tracking

内存采集本身占用的内存大小,如果没有打开采集,就不会占用,总内存大小不受限制,一般不会很大。

Shared class space

共享类空间占用的内存。

可以通过-Xshare:off关闭类共享空间,默认开启。

Arena Chunk

统计的ArenaChunk,是HotSpot自己定义的ArenaChunk,而不是Glibc中相关的ArenaChunk的概念。总内存大小不受限制,一般不会很大。

Tracing

包括JVM perf以及JFR占用的空间。

如果开启了JFR则主要是JFR占用的内存。总内存大小不受限制,一般不会很大,也可能因为JFR配置占用几百兆。

Module

Java 9模块化后,模块占用的内存。

Safepoint

JVM安全点占用内存,不会随着JVM运行时的内存占用而变化。

Synchronization

Java同步机制(例如synchronized,还有AQS的基础LockSupport)底层依赖的C++的数据结构,系统内部的mutex等占用的内存。

Serviceability

JVM TI(Java Virtual Machine Tool Interface)占用的内存。

Metaspace

Class中的MetaChunk(除了malloc的部分)

String Deduplication

Java字符串去重占用内存,去重机制可以减少应用程序中字符串对象的内存占用。

这个机制一直在某些GC下表现不佳,尤其是G1GC以及ZGC中,所以默认是关闭的。

可以通过-XX:+UseStringDeduplication来启用。

Unknown

Unknown有几种情况;

  • 当内存类别无法确定时;
  • Arena用作堆栈或值对象时;
  • 当类型信息尚未到达时。

参考

全网最硬核 JVM 内存解析 - 1.从 Native Memory Tracking 说起 https://juejin.cn/post/7225871227743043644

【技术剖析】15. Native Memory Tracking 详解(1):基础介绍 https://bbs.huaweicloud.com/forum/thread-0246998875346680043-1-1.html

【技术剖析】16. Native Memory Tracking 详解(2):追踪区域分析(一) https://bbs.huaweicloud.com/forum/thread-0295101552606827089-1-1.html

【技术剖析】17. Native Memory Tracking 详解(3):追踪区域分析(二) https://bbs.huaweicloud.com/forum/thread-0227103792775240073-1-1.html

【技术剖析】18. Native Memory Tracking 详解(4):使用 NMT 协助排查内存问题案例 https://bbs.huaweicloud.com/forum/thread-0211103793043202049-1-1.html

官方文档

https://docs.oracle.com/en/java/javase/17/vm/native-memory-tracking.html

https://docs.oracle.com/en/java/javase/17/troubleshoot/diagnostic-tools.html

https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/tooldescr007.html

Views: 451 · Posted: 2023-12-26

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb/LiteNote

扫描下方二维码关注公众号和小程序↓↓↓

扫描下方二维码关注公众号和小程序↓↓↓
Today On History
Browsing Refresh