我们正在AWS ECS中运行Java微服务。因此,对于Docker,我们使用-Xmx指定了一些硬Java堆限制。确定要为堆保留多少内存以及为非堆内存(元空间,堆栈,JIT缓存等)需要多少是非常棘手的部分。当前,我们正在运行压力测试以识别何时拥有Docker OOMKiller。
例如,对于2GB的AWS任务( docker ),最大可以为堆设置-Xmx1400m(对于-Xmx1450m,我们没有足够的内存来存储非堆的东西(退出代码137))
实际上,Java 10+具有“-XX:MaxRAMPercentage”,但是我们仍然需要知道该百分比。
如何确定Java微服务的堆大小/非堆大小? 还是压力测试是唯一的解决方案?
解决方案如下:
从Java 8u131开始,there is an option to set the JVM limits based on container memory limits。因此,如果您运行类似:
docker run \
-m 2g \ # set a container memory limit
openjdk:8 \
java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
com.example.Classname
JVM将设置堆限制,使其适合2 GB的容器内存限制,并为您运行
-Xmx
。原则上,这应该安排事情,以便您永远不会达到容器的内存限制,而是先获取Java
OutOfMemoryError
。
This blog post关于该主题还有更多示例,并且建议
-XX:MaxRamFraction=1
允许使用“所有内存”,在此您已通过
docker run -m
选项对其进行了限制。
实际上,您可能会在Dockerfile中设置
$JAVA_OPTS
,例如
FROM openjdk:8
COPY app.jar /
ENV JAVA_OPTS=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRamFraction=1
CMD ["java", "-jar", "/app.jar"]
然后像
docker run -d -p ... -m 2g myimage
在Kubernetes环境中,在pod的资源约束中声明的内存限制起着相同的作用。
正如@KarolDowbecki在他们的答案中建议的那样,您确实需要进行一些分析和监视才能为此实际选择正确的数字。在本地运行应用程序并监视
RSS
或
ps
中的
top
(居民集大小)统计信息应为您提供一个合理的基准。