已采纳
回答正文
回复
讨论正文
该问题的正文、回答与讨论。
【背景】 我做了 3 年运维,主责一条 Java 17 网关服务(Spring Boot 3,Netty 4.1,JDK 17.0.9,-Xmx3g -XX:MaxMetaspaceSize=256m),跑在 K8s 1.28 集群(cgroup v2,containerd 1.7),Pod request 4G / limit 8G。平时堆占用稳定在 1.2~1.5G,JMX 监控曲线看着非常健康。
【现象】
近 3 天,同一个 Pod(没有发版、没有流量突刺)的 cgroup memory.current 从 4.1G 缓慢爬到 5.8G,斜率约 30~50M/小时,非常线性。关键反常点:
pmap -x <pid> | awk '{s+=$2} END {print s}' 跟 memory.current 基本对得上,说明不是 page cache 的锅;-Dio.netty.leakDetection.level=PARANOID 开了 48 小时,一行 "LEAK" 日志都没有;-XX:MaxDirectMemorySize 没显式设(默认跟 -Xmx 一样 3G),但 jcmd <pid> VM.native_memory summary 里 Other 区块只涨了 800M,不是全部。也就是说,剩下那 700M~1G 的堆外增长,JVM 自己的工具链看不全,Netty 的 leak detector 也抓不到。
【已尝试的排查与结果】
cat /sys/fs/cgroup/.../memory.stat 对比 T0 和 T+48h:anon 涨了约 1.6G,file 几乎不动,slab 涨了 30M——确认是匿名页在涨,不是 page cache / 内核 slab。pmap -x <pid> 全量 dump 到本地,用 awk 按 size 排序看 top 20 大块:最大的几块都在 512M 级别,地址段不连续,怀疑是 glibc 的 malloc arena 碎片化 + DirectByteBuffer 混合,但光看 size 没法区分是哪一类。jcmd <pid> GC.heap_info + jmap -histo:live 对比,发现堆内对象数完全稳定,排除堆内慢漏。【期望得到的答案形态】 不重启、不装 agent、不换 allocator 的前提下,想请教:
memory.stat 的哪些字段组合(anon/file/slab/shmem 各涨了多少)能先做哪一档的排除?pmap 两次快照对比,除了看 size,还有哪些维度(如地址段连续性、对齐方式、/proc/<pid>/smaps 里的 VmPTE 或 RssAnon)能帮我区分 glibc arena 碎片 vs DirectByteBuffer vs mmap 的 native 分配(JNI / JNI 库) vs 线程栈?tcmalloc 热替换基本不现实,那还有别的路吗)?欢迎贴你们的实际命令输出片段(脱敏后),越具体越好。