bigywater.tech
Java · 207

NMT:追踪 JVM 堆外内存去了哪里

进程占了 1 GB 内存,堆只有 256 MB,剩下的去哪了?NMT 把 JVM 自己的内存按类别记账。这篇分五个阶段,每个阶段制造一类内存增长,看 NMT 的哪一项在涨、RSS 又怎么变(Metaspace 与堆外内存的专门篇目见前面)。

100.0 MB
10 个 DirectByteBuffer(100 MB)对应 NMT 的 Other 类别
642.7 MB vs RSS +37 MB
300 个线程:NMT Thread 类别 committed 与 RSS 的增量对比
1.12 MB
NMT summary 模式自身的内存

summary 的结构

实测 · 本机执行输出
  Native Memory Tracking:
  (Omitting categories weighting less than 1KB)
  Total: reserved=2013127KB, committed=181991KB
         malloc: 22159KB #6860
         mmap:   reserved=1990968KB, committed=159832KB
  -                 Java Heap (reserved=532480KB, committed=67584KB)
                              (mmap: reserved=532480KB, committed=67584KB, at peak) 
  -                     Class (reserved=1048657KB, committed=209KB)

分阶段的变化

实测 · 本机执行输出
类别                                    基线      +100 MB 堆外         +300 线程        +5000 个类     +200 MB 堆数组
TOTAL                              177.7           277.7           885.5           906.4          1106.5
Java Heap                           66.0            66.0            66.0            66.0           255.0
Class                                0.2             0.2             0.3             8.0             8.0
Thread                              36.3            36.3           642.7           642.7           650.8
Code                                 7.4             7.4             7.5             7.5             7.5
GC                                  51.8            51.8            51.9            51.9            55.9
Internal                             1.2             1.2             1.7             1.9             1.9
Other                                  -           100.0           100.0           100.0           100.0
Symbol                               1.1             1.1             1.1             1.5             1.5
Native Memory Tracking               0.1             0.1             0.3             1.1             1.1
Arena Chunk                          0.4             0.4             0.8             1.3             0.0
Metaspace                            0.3             0.3             0.3            10.9            10.9
Shared class space                  12.6            12.6            12.6            12.6            12.6
进程 RSS (ps)                           39             139             176             205             397

NMT 的开销

实测 · 本机执行输出
  Native Memory Tracking committed = 1.12 MB(占进程 RSS 397 MB 的 0.3%)

分步演示

NMT
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS,G1,-Xmx512m,NMT summary 模式
    • 没有验证:detail 模式与调用栈、summary.diff 输出(没有采用)、NMT 的 reserved 与 committed 的精确定义、容器内存限制下 RSS 与 NMT 的差异、线程栈 committed 偏大的原因(只观察到 committed 与 RSS 的差距);数字来自一次运行
    京ICP备2026067502号-1京公网安备11010502063487号