Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add script to make it easier to set Xmx values #71

Closed
wants to merge 1 commit into from

Conversation

carlossg
Copy link

From #59

A script to set better default Xmx values according to the docker memory limits from /sys/fs/cgroup/memory/memory.limit_in_bytes

If Xmx is not set the JVM will use by default 1/4th (in most cases) of the host memory
This can cause the Kernel to kill the container if the JVM memory grows over the cgroups limit
because the JVM is not aware of that limit and doesn't invoke the GC
Setting it by default to 0.5 times the memory limited by cgroups, customizable with JVM_HEAP_RATIO

Example

docker run -m 256m -e JVM_HEAP_RATIO=0.9 -ti --rm java /usr/local/bin/docker-jvm-opts.sh
-Xmx128m
docker run -m 256m -e JVM_HEAP_RATIO=0.9 -ti --rm java /usr/local/bin/docker-jvm-opts.sh
-Xmx230m

@flah00
Copy link

flah00 commented Mar 7, 2017

Is there any hope of merging this?

@ndeloof
Copy link
Contributor

ndeloof commented Apr 3, 2017

@tianon any chance to see this PR merged ?
we have been discussing depending on it for Jenkins docker official image
(jenkinsci/docker#451 (comment))

@carlossg
Copy link
Author

carlossg commented Apr 3, 2017

if we are ok to merge scripts for this, the implementation from fabric8 in jenkinsci/docker#451 (comment) is probably a better option

@tianon
Copy link
Member

tianon commented Apr 3, 2017

Sorry for the delay 😞

Isn't this something that a "good" value for varies from application to application? I seem to recall at least some instances where setting this value to something approaching the limit ended up with OOM issues due to threading, forking, etc. I can't seem to find where that discussion was, though (since it's not over in #59).

@carlossg
Copy link
Author

carlossg commented Apr 3, 2017

yes, it varies from application to application, but it would be nice to provide a sensible set of default values, or the scripts to calculate them to be used by downstream images in a consistent way

@hoshsadiq
Copy link

hoshsadiq commented Apr 5, 2017

@tianon as @carlossg said, it does vary per application. I think if there is a common approach (i.e. something provided by this image), it can make life easier for other images, included homegrown ones. As @carlossg said, the guys over at @fabric8io did a great job in writing a little script that does that, and makes it super simple to adjust the JVM limit by simply setting a environment variable (JAVA_MAX_MEM_RATIO, defaults to 50%).

@flah00
Copy link

flah00 commented Apr 5, 2017

As it stands, managing JVM inside a container is painful, because so often people set resource requests and limits. They do not set the JAVA_OPTS env var, to cap their heap. And, even when all of these settings are configured, it means updating three settings in two distinct places. This leaves a lot of room for error.

It seems like java 9 will have a switch, allowing it to check cgroup memory limits. But plenty of others will be stuck, in java 7 and java 8, without any simple solution.

I feel like the scripts devised by @carlossg and @fabric8io neatly button up legacy javas.

@yosifkit
Copy link
Member

yosifkit commented Apr 5, 2017

I'm 👍 to having some scripts similar to the ones in the Jenkins PR. The change I would make is to have java-default-options automatically source the container-limits script; that way a user can start up their container in a one-liner:

$ docker run -d my-java-image sh -c 'JAVA_OPTS="$JAVA_OPTS $(docker-java-default-options)" exec java /path/to/war'

@tianon mentioned he would rather have two single scripts that each get the corresponding value of cpu or memory as well as a third script to do the simple above docker-java-default-options. So something like the following would be possible. The previous example would still work, but this would offer flexibility to users over the bash functions.

$ docker run -d my-java-image sh -c 'JAVA_OPTS="$JAVA_OPTS -Xmx$(docker-java-memory-limit) -XX:ParallelGCThreads=$(docker-cpu-cores-limit)" exec java /path/to/war'

@hoshsadiq
Copy link

I will try and put a PR together for this weekend. Will take those suggestions into account while still using fabric8's scripts. Can anyone confirm the license will be compatible? Their scripts are under Apache2 license, this repo is under MIT.

@praseodym
Copy link

praseodym commented Apr 28, 2017

Java 8u131 includes the -XX:+UseCGroupMemoryLimitForHeap setting (see JDK-8175898) which allows setting maximum heap size in containers without scripting, e.g.:

java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=1 -XshowSettings:vm -version

@yosifkit
Copy link
Member

Oh, neat, though XX:MaxRAMFraction is unintuitive to me.

$ docker run -it --rm --memory 600m openjdk:9 java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:MaxRAMFraction=4 -XshowSettings:vm -version
VM settings:
    Max. Heap Size (Estimated): 150.00M
    Using VM: OpenJDK 64-Bit Server VM

openjdk version "9-Debian"
OpenJDK Runtime Environment (build 9-Debian+0-9b161-1)
OpenJDK 64-Bit Server VM (build 9-Debian+0-9b161-1, mixed mode)

@praseodym
Copy link

-XX:MaxRAMFraction=n specifies that the JVM will use a maximum of 1/n of total RAM as its heap size. The default is set to n=4, so with 600MB RAM the JVM will use 1/4*600 = 150M as the maximum heap size. Because the JVM also accounts for other overhead, setting n=1 will configure a maximum heap size of slightly less than 600MB.

@tianon
Copy link
Member

tianon commented May 8, 2017

Related docs PR: docker-library/docs#900

@tianon
Copy link
Member

tianon commented Nov 13, 2018

Closing old PR, especially given OpenJDK upstream support for handling cgroup limits. If there are further improvements to be made here, they should be proposed upstream with the OpenJDK project (who seem to be much more aggressively recently in both listening to community feedback and in implementing support for newish things like cgroups). 👍

@tianon tianon closed this Nov 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants