Java8应用Garbage Collector无日志输出且内存异常如何排查
故障排查步骤
1 优先解决GC日志无更新问题
你当前配置的GC参数仅开启了打印开关,缺少必要的输出配置,先按以下步骤校验:
- 核对完整GC参数:默认
-XX:+PrintGC等打印参数会将日志输出到stdout,如果你使用容器部署,stdout通常会被日志采集组件统一收集,不会生成本地文件。需要补充以下参数指定本地输出路径(注意路径需要给Java进程开放读写权限):
-Xloggc:/your/log/path/gc.log -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=100M -XX:+PrintGCDateStamps -XX:-UseGCLogFileBuffer
其中-XX:-UseGCLogFileBuffer用来关闭GC日志缓冲,避免缓冲未写满导致日志不落地的问题。
- 验证参数生效:执行
jps -v [Java进程ID]查看运行中进程的实际启动参数,确认GC相关配置没有被启动脚本、镜像默认参数覆盖。
2 确认GC是否正常触发
不需要等日志输出,用JDK自带工具即可实时观测GC运行状态:
- 执行
jstat -gcutil [Java进程ID] 2000 10,每2秒输出一次GC统计数据,连续观测10次。如果YGC(Young GC次数)、FGC(Full GC次数)、YGCT/FGCT(GC累计耗时)数值有增长,说明GC正常运行,问题仅出在日志配置上;如果以上数值长期无变化,说明GC确实没有触发,内存上涨大概率来自堆外内存泄漏。 - 你本地堆dump分析正常、线上内存持续上涨但GC不触发,是典型的堆外内存泄漏特征:JDK8的Metaspace、Direct ByteBuffer、JNI申请的Native内存都不受
-Xmx堆上限限制,这部分内存泄漏会导致POD整体内存占用上涨,但堆内内存一直没达到阈值,所以GC不会触发,直到POD达到资源上限被系统强制杀死。
3 内存泄漏排查方案
3.1 堆外内存排查
- 新增启动参数限制堆外内存上限:
-XX:MaxDirectMemorySize=2G,如果之后出现OutOfMemoryError: Direct buffer memory报错,即可确认是直接内存泄漏。 - 开启Native内存追踪:新增启动参数
-XX:NativeMemoryTracking=summary,进程运行期间执行jcmd [Java进程ID] VM.native_memory summary,观测Internal、Direct分类的内存占用变化,定位泄漏来源。
3.2 容器适配校验
如果你的JDK8版本低于8u191,默认无法识别CGroup资源限制,会按宿主机总内存分配堆大小,导致实际内存超过POD配置的上限被OOM Kill。需要新增启动参数:
-XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=2
让JVM按照容器的内存配额分配堆空间。
3.3 堆内泄漏排查
GC日志配置生效后,新增参数-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/your/dump/path,发生OOM时会自动生成堆dump文件,用MAT工具分析即可定位堆内泄漏点。
内容的提问来源于stack exchange,提问作者Ailu Vee
相关产品推荐
相关产品推荐

