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
base: master
from

Conversation

Projects
None yet
7 participants
@carlossg

carlossg commented Mar 16, 2016

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

This comment has been minimized.

flah00 commented Mar 7, 2017

Is there any hope of merging this?

@ndeloof

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

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

This comment has been minimized.

hoshsadiq commented Apr 6, 2017

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

This comment has been minimized.

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

This comment has been minimized.

Member

yosifkit commented Apr 28, 2017

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

This comment has been minimized.

praseodym commented Apr 28, 2017

-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

This comment has been minimized.

Member

tianon commented May 8, 2017

Related docs PR: docker-library/docs#900

@tianon

This comment has been minimized.

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