如何规避容器内做Java堆dump导致容器崩溃的问题
写在前边最近公司生产环境的容器云上出了个性能问题,为了做性能分析,使用 JDK 自带的 jmap 收集堆dump,出现了内存溢出导致了容器崩溃。本篇文章将带你探究,如何规避容器内做堆 dump 导致容器崩溃的问题。适用于低于 Java 8 update 191版本的 JDK。分析容器崩溃原因确认容器崩溃的根本原因毋庸置疑的是容器的内存占用超过了容器的限制,被 k8s 或 docker kill 掉
写在前边
最近公司生产环境的容器云上出了个性能问题,为了做性能分析,使用 JDK 自带的 jmap
收集堆dump,出现了内存溢出导致了容器崩溃。
本篇文章将带你探究,如何规避容器内做堆 dump 导致容器崩溃的问题。适用于低于 Java 8 update 191版本的 JDK。
分析容器崩溃原因
确认容器崩溃的根本原因
毋庸置疑的是容器的内存占用超过了容器的限制,被 k8s 或 docker kill 掉了。
为什么会超过容器的限制呢?
有两种可能:
- Java 应用服务内存仍在攀升,就算不操作也会崩溃
jmap
收集堆dump时占用内存所致
根据容器云平台的运维人员提供的监控截图,基本确认是第二种情况。
Ps: GMT时间+8小时即北京时间,18点左右出现容器内存急剧攀升的情况,而此时正在收集堆dump
为什么 jmap 会申请超过容器限制的内存呢?
首先,我们需要知道 jmap 本身是启动了另一个 JVM 来收集问题应用的 JVM堆的信息的。提到 JVM 运行在容器里会出现的问题,第一个就应该想到 JVM 对容器环境的支持问题,即低于 Java 8 update 191 版本的 JDK 会直接读到物理节点的内存,从而根据物理节点去申请内存,直接导致了容器崩溃。
本次环境就是 OpenJDK 8 低于 191 的版本,所以原因找到了。
解决方案
参考了两个版本的 jmap 官方文档,发现有个可以配置 jmap 所在 JVM 的参数 -Jflag
JDK 7
-J<flag>
Passes <flag> to the Java virtual machine on which jmap is run.
JDK 8
-Jflag
Passes flag to the Java Virtual Machine where the jmap command is running.
这里笔者确认了下这个flag参数最终传递到的是 jmap 所在的 JVM 中,而不是应用服务 JVM
所以方案就比较简单了,根据容器除应用服务 JVM 堆及元空间内存外的可用内存,设置个合理的JVM即可。
示例:容器限制 32G 内存,应用服务堆占用 24G,元空间占用 2G,则可用内存在 6G以下。给容器预留 1G 内存防止其崩溃,可以设置 jmap 使用 5G。
命令格式:jmap [输出dump文件配置] [设置jmap虚拟机参数] [进程号]
jmap -dump:format=b,file=/deployments/heap.hprof -J-Xmx5g 1
参考文档:
https://docs.oracle.com/javase/7/docs/technotes/tools/share/jmap.html
https://docs.oracle.com/javase/8/docs/technotes/tools/unix/jmap.html
本文同步发表在笔者博客园[https://www.cnblogs.com/hellxz/]与CSDN[https://blog.csdn.net/u012586326],禁止转载。
更多推荐
所有评论(0)