java - 自动配置 Java 以使用分配给其 Docker 容器的最大 RAM

标签 java bash docker

如果我使用 docker run --memory=X 通过 Bash 脚本运行 Java 应用程序,有没有办法让这个 Bash 脚本可靠地推断如何为容器分配了多少内存?基本上,我希望这个 Bash 脚本执行以下操作:

#!/bin/bash

# (Do some other stuff...)

MAX_RAM="$(get-max-ram)"
exec java "-Xms${MAX_RAM}" "-Xmx${MAX_RAM}" -jar my_jar.jar

另外,如果我执行上述操作,我是否应该让 Java 使用比最大 RAM 少一点?

最佳答案

Docker 使用 cgroups实现资源限制。在容器内,您可以使用 cgget实用程序,用于打印各种子系统(在本例中为 memory 子系统)的参数。

例如,考虑一个内存限制为 64G 的容器(毕竟是 Java):

> docker run --memory=64G

在容器内,然后使用cgget读取memory.limit_in_bytes参数的当前值:

> cgget -nvr memory.limit_in_bytes /
68719476736

请注意,您可能必须首先通过容器镜像的包管理器安装 cgget 二进制文件。在 Ubuntu 上,您需要 cgroup-bin 包。

然后您可以使用此值来动态计算您的 JVM 参数(仅作为示例,根据您自己的需要进行调整):

MAX_RAM=$(cgget -nvr memory.limit_in_bytes /)
JVM_MIN_HEAP=$(printf "%.0f" $(echo "${MAX_RAM} * 0.2" | bc))
JVM_MAX_HEAP=$(printf "%.0f" $(echo "${MAX_RAM} * 0.8" | bc))
exec java "-Xms${JVM_MIN_HEAP}" "-Xmx${JVM_MAX_HEAP}" -jar my_jar.jar

重要:在没有内存限制的情况下运行时(即没有 --memory=X 标志),memory.limit_in_bytes 参数仍然有一个值,尽管大小约为 2^63 - 4096:

> cgget -nvr memory.limit_in_bytes /
9223372036854771712

除非您想以大约 8 EB 的最小堆空间启动 JVM,否则您的入口点脚本也应该考虑这种情况:

MAX_RAM=$(cgget -nvr memory.limit_in_bytes /)
if [ $MAX_RAM -le 137438953472 ] ; then
    JVM_MIN_HEAP=$(printf "%.0f" $(echo "${MAX_RAM} * 0.2" | bc))
    JVM_MAX_HEAP=$(printf "%.0f" $(echo "${MAX_RAM} * 0.8" | bc))
else
    JVM_MIN_HEAP=32G
    JVM_MAX_HEAP=128G
fi

exec java "-Xms${JVM_MIN_HEAP}" "-Xmx${JVM_MAX_HEAP}" -jar my_jar.jar

关于java - 自动配置 Java 以使用分配给其 Docker 容器的最大 RAM,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34594575/

相关文章:

java - 是否可以只针对一个 Java 类运行 FindBugs?

bash - getopts 没有解析我的命令行选项

bash - 如何使用 shell 脚本将一个文件内容合并/附加到另一个文件

nginx - Docker - index.html Nginx 文件共享无效

linux - 如何从外部访问 Weave DNS-Server?

java - 使用这些垃圾收集设置的 JVM 性能

java - 如何导入字体?

从 Java 9 开始,javassist.NotFoundException

linux - bash 脚本中的 curl 请求在 URL 中需要美元符号

java - 为什么Docker容器的内存使用量不会减少?