k8s之容器内存与JVM内存

  • Post author:
  • Post category:其他


容器内的 Java 应用可能会发生两种类型的 OOM 异常,


JVM 的 OOM



JVM 的堆栈元空间等内存泄漏

,导致没有足够的内存来为对象分配空间并且GC也没有空间可回收时,这时JVM会主动抛出错误并退出进程,并留下相应的错误记录。容器退出状态为exit code 137 reason: error(

137表示容器收到SIGKILL信号而失败,通常是达到资源限制或探针失败


容器 OOM



一般是JVM参数设置不合理

,导致container_memory_working_set_bytes达到了cgroups限制,会在k8s事件中记录且容器退出状态为exit code 137 reason: OOM Killed

从容器来看

container_memory_working_set_bytes代表容器真实使用的内存量,也是判断超过limit的限制,超过limit则会导致oom;

container_memory_working_set_bytes = container_memory_usage_bytes – total_inactive_file(不活跃缓冲页);

container_memory_usage_bytes = container_memory_rss(进程实际使用的物理内存)+container_memory_cache(页面缓存)+kernel memory;

container_memory_cache = total_active_file + inactive_file;

从jvm来看

进程实际使用的物理内存container_memory_rss = JVM内存(堆栈元空间)+直接内存+其他(文件描述符、GC消耗等等);

容器真实使用的内存量container_memory_working_set_bytes = JVM内存(堆栈元空间)+直接内存+其他(文件描述符、GC消耗等等)+container_memory_cache(页面缓存)+kernel memory;

而预留内存又=直接内存+其他(文件描述符、GC消耗等等)+container_memory_cache(页面缓存)+kernel memory;

综上,容器真实使用的内存为

JVM内存(堆栈元空间)+ 预留内存(直接内存+文件描述符、GC消耗等 + 活跃的缓存页 + kernel memory)

一种解决 JVM 内存超限的方法

可以让 JVM 自动感知 docker 容器的 cgroup 限制,从而动态的调整堆内存大小。JDK8u131 在 JDK9 中有一个很好的特性,即 JVM 能够检测在 Docker 容器中运行时有多少内存可用。为了使 jvm 保留根据容器规范的内存,必须设置标志 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap。

注意:如果将这两个标志与 Xms 和 Xmx 标志一起设置,那么 jvm 的行为将是什么?

-Xmx 标志将覆盖-XX:+ UseCGroupMemoryLimitForHeap 标志。

MaxDirectMemorySize

-XX:MaxDirectMemorySize=size用于设置New I/O(

java.nio

) direct-buffer allocations的峰值,-XX:MaxDirectMemorySize 没显式配置的时候,NIO direct memory 可申请的空间的上限就是 -Xmx 减去一个 survivor space 的预留大小。如果不配置

-XX:MaxDirectMemorySize

并配置 -Xmx5G,则 默认 MaxDirectMemorySize 也将是 5G-survivor space 区,并且应用程序的总堆+直接内存使用量可能会增长到

5G + 5G = 10 G



版权声明:本文为qq_34562093原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。