我正在调查从 Glassfish/Java 8 移植的 Java 17 spring boot 3 应用程序中的内存问题。它在 kubernetes 上运行。
最终,containerd 在达到容器内存限制时会 oom-killing java 进程。 jconsole 中的监控显示 gc 将堆轻松保持在 3.5Gib 之内。启用 NMT(本机内存跟踪器)不会显示任何关注大小的非堆内存池。
我还使用 NMT 在运行“堆密集型”短期作业之前生成基线,然后在完成后与该基线进行比较。我还使用 jconsole 和
top
进行监控。我发现top
报告作业执行导致java进程中RES内存永久增加;即使 jconsole 或 NMT 都没有表明任何原因。
对于 NMT 的承诺总额:
top
。即进程驻留内存为 3.1Gib(奇怪??)通过此作业执行使用 jconsole 显示堆使用情况很好地保持在 -Xmx 和执行其作业的常规 gc 周期内;作业结束后堆使用率恢复到正常水平。
NMT 输出:
创建预运行基线:
[root@host-1 opt]# sudo -u appuser /opt/java/openjdk/bin/jcmd 191 VM.native_memory baseline
191:
Baseline succeeded
然后发布作业生成差异:
[root@host-1 opt]# sudo -u appuser /opt/java/openjdk/bin/jcmd 191 VM.native_memory summary.diff
191:
Native Memory Tracking:
(Omitting categories weighting less than 1KB)
Total: reserved=5558072KB +11469KB, committed=4778088KB +22493KB
- Java Heap (reserved=3670016KB, committed=3670016KB)
(mmap: reserved=3670016KB, committed=3670016KB)
- Class (reserved=331083KB +223KB, committed=26571KB +543KB)
(classes #33968 +545)
( instance classes #31813 +515, array classes #2155 +30)
(malloc=3403KB +223KB #83118 +5582)
(mmap: reserved=327680KB, committed=23168KB +320KB)
: ( Metadata)
( reserved=196608KB, committed=161088KB +4736KB)
( used=160529KB +4619KB)
( waste=559KB =0.35% +117KB)
: ( Class space)
( reserved=327680KB, committed=23168KB +320KB)
( used=22637KB +321KB)
( waste=531KB =2.29% -1KB)
- Thread (reserved=192733KB +9279KB, committed=20945KB +995KB)
(thread #0)
(stack: reserved=192188KB +9252KB, committed=20400KB +968KB)
(malloc=327KB +16KB #1128 +54)
(arena=218KB +11 #373 +18)
- Code (reserved=254471KB +1005KB, committed=105347KB +15257KB)
(malloc=6787KB +1005KB #31852 +3340)
(mmap: reserved=247684KB, committed=98560KB +14252KB)
- GC (reserved=243202KB +494KB, committed=128490KB +494KB)
(malloc=13346KB +494KB #39503 +4498)
(mmap: reserved=229856KB, committed=115144KB)
- Compiler (reserved=1237KB +48KB, committed=1237KB +48KB)
(malloc=1072KB +48KB #3239 +180)
(arena=165KB #5)
- Internal (reserved=7246KB +271KB, committed=7246KB +271KB)
(malloc=7210KB +271KB #38329 +4138)
(mmap: reserved=36KB, committed=36KB)
- Other (reserved=587124KB +186KB, committed=587124KB +186KB)
(malloc=587124KB +186KB #99 +6)
- Symbol (reserved=38580KB +343KB, committed=38580KB +343KB)
(malloc=36334KB +279KB #888476 +9518)
(arena=2246KB +64 #1)
- Native Memory Tracking (reserved=17131KB +436KB, committed=17131KB +436KB)
(malloc=38KB +1KB #573 +12)
(tracking overhead=17093KB +435KB)
- Shared class space (reserved=16384KB, committed=12056KB)
(mmap: reserved=16384KB, committed=12056KB)
- Arena Chunk (reserved=479KB -991KB, committed=479KB -991KB)
(malloc=479KB -991KB)
- Tracing (reserved=32KB, committed=32KB)
(arena=32KB #1)
- Module (reserved=792KB +93KB, committed=792KB +93KB)
(malloc=792KB +93KB #4842 +285)
- Safepoint (reserved=8KB, committed=8KB)
(mmap: reserved=8KB, committed=8KB)
- Synchronization (reserved=150KB +11KB, committed=150KB +11KB)
(malloc=150KB +11KB #1575 +105)
- Serviceability (reserved=1KB, committed=1KB)
(malloc=1KB #12)
- Metaspace (reserved=197375KB +59KB, committed=161855KB +4795KB)
(malloc=767KB +59KB #558 +81)
(mmap: reserved=196608KB, committed=161088KB +4736KB)
- String Deduplication (reserved=1KB, committed=1KB)
(malloc=1KB #8)
- Object Monitors (reserved=29KB +13KB, committed=29KB +13KB)
(malloc=29KB +13KB #141 +66)
[root@host-1 opt]#
字段 RES 的含义(驻留内存大小,以 KiB 为单位):代表虚拟内存空间 (VIRT) 的子集,表示任务当前使用的非交换物理内存。
这证实了我的预期,即 RES 应与 NMT 承诺总量相当接近。请注意,这篇文章是相关的,但没有回答我的问题:Difference between Resident Set Size (RSS) and Java Total Commited Memory (NMT) for a JVM running in Docker container - 似乎更表明 NMT 总提交量可能经常高于 RES - 与我所看到的相反。
我的问题是:
top
RES头值(4.9Gib)和java的NMT总提交量(3.5Gib)之间存在这样的差异?同样的问题。
我的 pmap 显示 64MB 对,如 this ,并设置环境变量 MALLOC_ARENA_MAX=1 或切换到 jemalloc 确实解决了我的问题。
为此还存在一个 open jdk 问题。