Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker 诊断工具


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

NMT JVM Java 大约 8639 字

开启 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

阅读 135 · 发布于 2023-12-26

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

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

扫描二维码关注我
昵称:
随便看看 换一批