Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automatically configure Java to use the maximum RAM allocated to its Docker container

Tags:

java

bash

docker

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?

like image 795
Gus Avatar asked Jan 04 '16 15:01

Gus


People also ask

How do I set max RAM for Java?

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.

How do I assign more memory to a Docker container?

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.

What is the maximum amount of RAM a container can consume?

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.

How much RAM should I allocate to Docker?

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.


2 Answers

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
like image 124
helmbert Avatar answered Oct 27 '22 23:10

helmbert


  • 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:

  • http://royvanrijn.com/blog/2018/05/java-and-docker-memory-limits/
  • https://blog.docker.com/2018/04/improved-docker-container-integration-with-java-10/
  • https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits
  • http://hg.openjdk.java.net/jdk/jdk/file/03f2bfdcb636/src/hotspot/os/linux/osContainer_linux.cpp
like image 39
qudongfang Avatar answered Oct 28 '22 00:10

qudongfang