内容简介:在这意味着应用程序消耗的内存比分配给容器的内存多。这听起来不对,因为我们使用-Xmx对Java应用程序进行了限制,并且我们为元空间和GC数据留下了大约20%的缓冲区作为Kubernetes资源限制(docker容器)。例如,Java进程为2 GB,Kubernetes资源为2.4 GB。
在 Logistimo ,我们的所有应用程序都是 Docker 化的,并在Kubernetes内以docker容器运行。我们注意到在使用 Java 的容器上发生了大量重启,并且非常随机。Docker检查发现该pod被OOMKiller代码杀死:137。
这意味着应用程序消耗的内存比分配给容器的内存多。这听起来不对,因为我们使用-Xmx对Java应用程序进行了限制,并且我们为元空间和GC数据留下了大约20%的缓冲区作为Kubernetes资源限制(docker容器)。
例如,Java进程为2 GB,Kubernetes资源为2.4 GB。
后续部分将介绍此问题以及如何详细解决此问题。
JVM内存使用情况
第一步是检查容器超出上述限制的原因,显然这些是被缓冲充分利用了。
使用“ps”命令可以确认Xmx确实就位,并设置为最大4GB。
但是,“top”命令显示使用的物理内存为4.5 GB。
为什么Java会比分配多500 MB?
JDK 从1.8.40开始,引入了一个 Native内存跟踪器工具 ,它提供了Java应用程序使用的内存的详细分解,并考虑了每个字节。请注意,NMT工具显示已提交,驻留可能更少。
实际使用=堆内存+元空间+Off堆
Off heap通常由类元数据,编译代码,线程和GC数据组成。GC数据是可变的,而其余部分应该对大多数应用程序保持静态。此内存是本机的( 是的,包括元空间 ),JVM使用主机上的可用内存来增长或垃圾收集此数据。
鼓励你阅读 米哈伊尔这篇优秀的博客文章, 以获得更好的观点。
回到手头的问题,JVM占用了500 MB,因为底层主机有16 GB的存储空间。有时这个数字可能高于我们设置的缓冲区,这将导致容器被终止。JVM不应该读取docker容器的内存限制吗?
容器和Java
事实证明,Java版本9及以下版本根本不了解容器/Docker(默认情况下)。它从底层主机中获取可用的CPU和内存。在容器内的主机上运行的每个Java应用程序都依赖于主机配置。考虑到我们是Kubernetes并且许多pod在单个节点上运行,这可能会导致我们面临的问题。
Java 10支持开箱即用的容器,它将查找linux cgroup信息。这允许JVM基于容器限制进行垃圾收集。默认情况下使用标志打开它。
-XX:+UseContainerSupport
值得庆幸的是,其中一些功能已被移植到8u131和9以后。可以使用以下标志打开它们。
-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
总结
较旧版本的Java读取底层主机,并且不了解cgroup。这会导致容器配置和Java进程不匹配。这种不匹配在CPU和内存上。Java有一个Off堆内存组件,它有一个动态GC数据组件,可以增长。解决此问题的最佳方法是使用最新版Java中提供的容器支持功能。不要依赖缓冲(这是浪费钱)。
如果您必须继续使用这些主要版本并打开实验标志,请升级到Java 8u131 +或Java 9。更好的是,如果你可以获得Java 10以上将对所有容器有好处。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learn Python the Hard Way
Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99
Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!