针对Docker和DC / OS的JVM优化

我正在将一个裸机Java应用程序(jar jdk8)移动到Docker容器和DC / OS。 我在docker上注意到一个奇怪的模式,我们将-XMX设置为32位,并分配一个36位的docker集装箱。 每隔几个小时左右,应用程序就会在旧的gen mem分配中激增,并且在尝试执行堆转储时,GC将陷入循环(最大CPU)。

有什么优化或者我可以用来看看为什么在这个1-5秒的时间间隔里,我们的速度如此之快? 是否有任何我可能需要知道与Docker和JVM的陷阱?

我们正在使用默认的GC

仅供将来参考:

我们正在使用JDK 8,而且似乎Oracle最近刚刚添加了一些使用Docker的实验性标志。 我相信这种情况可能是GC分配线程时,它不是来自cgroup的docker线程数。 实验性的标志似乎已经解决了我们的“脱轨问题”

https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits

通常情况下,如果您有可能使用像DC / OS这样的容器平台,您希望避免使用大于30GB的内存的巨大应用程序,并将应用程序分割为更小的内存需求。

一般情况下,关于GC和堆大小:如果您的堆大,整个GC可能需要很长时间。 就我个人而言,我经历了完整的GC冻结了一分钟或更长时间,堆栈大小与您提到的30GB非常相似。

关于容器中的Java:JVM实际上比使用-Xmxconfiguration需要更多的内存。 因此,如果您在DC / OS(Marathon)应用程序中指定了2GB的内存限制,则不能设置-Xmx2G ,因为此内存限制是一个硬性限制。 如果您的容器内的进程将超过这些内存限制,容器将被杀死。 由于JVM将保留比configuration-Xmx更多的内存,这确实很可能发生。 一般来说,我会build议大约75%的configuration内存作为-Xmx值。

你可以看看更新的JRE版本,它支持-XX:+UseCGroupMemoryLimits 。 这是使用cgroup容器限制消耗内存的JRE标志,有关更多信息,请参阅https://developers.redhat.com/blog/2017/04/04/openjdk-and-containers/