为什么我通过Docker获得OOM?

时间:2019-05-18 13:32:49

标签: java docker garbage-collection

我有Java应用程序,包装在Docker中并托管在Amazon ECS上。

主要技术是:

  • SpringBoot 2
  • Java 8
  • 具有4Gb RAM的EC2 VM

每1-2天,应用程序崩溃,并被亚马逊服务重新唤醒。

在Docker昆虫的驱使下,我找到了原因:

"OOMKilled": true,

我已将执行器连接到CloudWatch,并且发现内存消耗曲线有奇怪的行为:

Memory consumption

那些蓝色的峰值是应用程序崩溃的时刻。

我已经了解到Java 8在正确读取主机的最大内存方面存在一些问题,但是:

1)Docker从应该解决问题的标志开始

ENTRYPOINT exec java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -Xms300M -XX:PermSize100M -Djava.security.egd=file:/dev/./urandom -jar /app.jar

2)无论如何,VM具有4Gb内存,因此〜1.3Gb峰值很高,不应杀死应用程序。

3)高峰时服务器上没有任何负载

1 个答案:

答案 0 :(得分:1)

  

-XX:PermSize100M

不适用于Java 8。

  

-XX:MaxRAMFraction = 1

这告诉JVM, java对象的托管堆的最大值是所有可用内存。但是JVM分配的内存不仅仅是为Java对象分配的。例如。元空间,打开文件的字节缓冲区,已加载的本机库等。

您应该执行以下操作之一:

  • 使用MaxRAMFraction=2代替1
  • 手动将Xmx设置为低于可用内存的值
  • 升级到Java> = 11并使用MaxRAMPercentage进行更细粒度的控制
  • 启用交换功能以使更多的内存溢出到磁盘

有关更新的Java版本的其他信息,另请参见"Is -XX:MaxRAMFraction=1 safe for production in a containered environment?"