Java17 ZGC下RSS持续增长但NMT无对应增长的问题
核心原因解析
出现RSS持续增长但NMT提交内存未同步增长的情况,主要和ZGC在低Linux内核版本下的tmpfs堆实现、Linux内存统计逻辑以及NMT的统计范围差异有关,具体如下:
1. ZGC tmpfs堆的物理内存占用不影响NMT提交内存统计
Linux内核低于3.17时,ZGC通过tmpfs创建堆内存区域。ZGC会预提交整个堆的虚拟内存(对应-Xmx设置的值),这部分预提交内存会被NMT统计为堆的提交内存,且在应用运行过程中基本保持固定(不会随负载增长而明显变化)。但当应用实际使用堆内存时,tmpfs中的虚拟内存会被映射到物理内存页,这部分物理内存会被Linux计入RSS,但NMT的提交内存统计不会因此变化——因为提交内存统计的是虚拟内存分配量,而非实际物理内存使用量。
2. NMT未覆盖部分ZGC堆外开销
在低内核版本的tmpfs堆模式下,ZGC需要额外内存结构管理tmpfs堆,比如:
- 跟踪tmpfs内存页的元数据
- 内存映射相关的页表开销
- 垃圾回收过程中的临时内存结构
这些内存属于堆外范畴,但未被NMT的提交内存统计完全覆盖,导致RSS统计的实际物理内存(包含这些未统计开销)大于NMT报告的提交内存总量。
3. Linux与NMT的内存统计定义存在差异
- Linux的RSS统计包含进程实际占用的所有物理内存页,包括tmpfs堆的物理使用、未被NMT统计的堆外开销,以及内核为进程分配的辅助内存(如与进程相关的文件系统缓存页)。
- NMT的提交内存仅覆盖Java虚拟机主动分配的虚拟内存区域,对于内核层面自动分配的内存(如tmpfs页表)、未被VM追踪的堆外内存,不会计入提交内存。
4. Java 17.0.7的未修复已知问题
你提到的类似已知问题在Java 17.0.7中未得到修复,说明该版本ZGC在低内核tmpfs模式下,确实存在内存统计不一致或未被NMT覆盖的堆外内存开销累积问题,高负载场景下这些开销持续增长,最终导致RSS上升但NMT提交内存无明显变化。
内容的提问来源于stack exchange,提问作者Nick Allen
相关产品推荐
相关产品推荐

