JVM 的启动命令一般都会加上参数 -XX:+HeapDumpOnOutOfMemoryError=/path/to/save/dump.hprof
,用于在 JVM 发生 OOM 时自动生成内存 dump 文件。
应用在生产环境是运行在 Docker 容器里、由 K8S 负责管理容器。
但是有的应用发生 OOM 时,在 /path/to/save/dump.hprof
路径下并没有生成对应的 dump 文件。
优秀的运维同事小伍在测试环境进行了各种测试,得出以下两种情况没法生产文件:
1. /path/to/save/
如果中间层的目录没有提前建好,是没法生成 dump 文件的。
2. 堆外内存不足 800M 时,也没法生成 dump 文件。
第1点没啥问题,文件所在的目录没有提前建好是会报 java.io.FileNotFoundException
异常的。
第2点其实是因为 JVM 运行在容器里,容器允许使用的内存是有上限的,比如分配给容器的是 4G 内存,JVM 堆占用 80%,那么堆外内存就只能占用 20% 即 800M。
发生 OOM 时,JVM 占用了 3.2G;对于堆外内存,线程、JVM自身、应用申请的本地内存等都要在这里分配,OOM dump 也需要利用堆外内存,容器使用的总内存达到 4G 内存上限时,触发系统的 oomkiller 机制把容器进程杀死。
这带来一个小问题:如果要保证 JVM OOM 自动 dump 机制能顺利执行,我们就需要在容器里预留出足够的堆外内存,每个容器都得考虑预留,这就带来内存利用率的问题了。如果 JVM 直接运行在宿主操作系统,没有容器的限制,能申请的堆外内存是受限于系统能分配的内存的,不同应用的 JVM 可共享这个可分配内存空间。
欢迎关注我的微信公众号: coderbee笔记 ,可以更及时回复你的讨论。