If I do docker run --memory=X
to run a Java app through a Bash script, is there any way to get this Bash script to reliably infer how much memory has been allocated to the container? Basically, I want this Bash script to do something like:
#!/bin/bash
# (Do some other stuff...)
MAX_RAM="$(get-max-ram)"
exec java "-Xms${MAX_RAM}" "-Xmx${MAX_RAM}" -jar my_jar.jar
Also, if I do the above, should I make Java use a little bit less than the maximum RAM?
The short answer is that you use these java command-line parameters to help control the RAM use of application: Use -Xmx to specify the maximum heap size. Use -Xms to specify the initial Java heap size. Use -Xss to set the Java thread stack size.
Set Maximum Memory Access To limit the maximum amount of memory usage for a container, add the --memory option to the docker run command. Alternatively, you can use the shortcut -m . Within the command, specify how much memory you want to dedicate to that specific container.
Limiting Memory This sets a hard limit. That means that under no circumstances will the container be allowed to use more than 256 MB of RAM.
Limit a container's access to memory The maximum amount of memory the container can use. If you set this option, the minimum allowed value is 6m (6 megabytes). That is, you must set the value to at least 6 megabytes. The amount of memory this container is allowed to swap to disk.
Docker uses cgroups to implement resource limits. Inside the container, you can use the cgget
utility, to print parameters of various subsystems (in this instance, the memory
subsystem).
For example, consider a container started with a memory limit of 64G (it's Java, after all):
> docker run --memory=64G
Within the container, then use cgget
to read the current value of the memory.limit_in_bytes
parameter:
> cgget -nvr memory.limit_in_bytes /
68719476736
Note that you'll probably have to install the cgget
binary via the container image's package manager first. On Ubuntu, you'll need the cgroup-bin
package.
You can then use this value to dynamically compute your JVM parameters (just as an example, adjust to your own needs):
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
Important: When run without memory restriction (i.e. without --memory=X
flag), the memory.limit_in_bytes
parameter will still have a value, although of the magnitude of around 2^63 - 4096:
> cgget -nvr memory.limit_in_bytes /
9223372036854771712
Unless you want to start your JVM with a minimum heap space of about 8 EB, your entrypoint script should also consider this case:
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
java5/6/7/8u131-: a simple but efffective method, You can use java -Xmx cat /sys/fs/cgroup/memory/memory.limit_in_bytes
(except windows)
java8u131+ and java9+: -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap
would do the job.
java 8u191+: UseContainerSupport
is turned on by default. This feature is backported from java10, but it hasn't been backported to java9 so far.
java10+: UseContainerSupport
is turned on by default.
Ref:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With