我正在Docker容器中运行一个Java程序,该容器具有4GB的硬内存限制。我已将最大堆设置为3GB,但仍然超出限制,并被杀死(OOMKilled)。
我的问题是: 如何配置Java以遵守设置的容器限制,并抛出OutOfMemoryException而不是尝试分配超出限制并被主机内核处理?
更新: 我是一名经验丰富的Java开发人员,并且对JVM有相当的了解。我知道如何设置最大堆,但我想知道是否有一种方法可以将JVM进程从操作系统中要求的总内存限制。
$ java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar
例如:
运行应用程序的命令将会像这样:
$ java ${JAVA_OPTIONS} -jar app.jar
而 docker run 命令需要像这样传递 ENV 变量:
$ docker run -e JAVA_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" myJavaImage
cgroup namespace
类型自2016年3月以来就已经存在于Linux 4.6中。那么,这种新的cgroup namespace
有什么意义呢?为什么应用程序(如JVM)需要关心添加容器支持?Docker引擎,例如containerd
应默认具备此功能。这确实有些难以理解。 - user14305942-XX:MaxRAMPercentage=50
要尝试 Java 10,请运行以下 Docker 命令:
docker run -it --rm -m1g --entrypoint bash openjdk:10-jdk
它将为您提供一个bash环境,您可以在其中运行JDK中的可执行文件。例如,要运行一个小脚本,您可以像这样使用jrunscript
:
jrunscript -e "print(Packages.java.lang.Runtime.getRuntime().maxMemory()/(1<<20) + 'M')"
这将显示堆大小(以MB为单位)。要更改用于堆的总容器内存百分比,请添加MaxRAMPercentage
参数,如下所示:
jrunscript -J-XX:MaxRAMPercentage=50 -e "print(Packages.java.lang.Runtime.getRuntime().maxMemory()/(1<<20) + 'M')"
java
控制台命令。对于未来的读者来说,评论中的更新可能不够明显。谢谢! - halfer