title: How do I elegantly and safely maximize the amount of heap space allocated to a Java application in Kubernetes?
body: <p>I have a Kubernetes deployment that deploys a Java application based on the <a href="https://hub.docker.com/r/anapsix/alpine-java/" rel="nofollow noreferrer">anapsix/alpine-java</a> image. There is nothing else running in the container expect for the Java application and the container overhead.</p>
  <p>I want to maximise the amount of memory the Java process can use inside the docker container and minimise the amount of ram that will be reserved but never used.</p>
  <p><strong>For example I have:</strong></p>
  <ol>
  <li><strong>Two Kubernetes nodes that have 8 gig of ram each and no swap</strong></li>
  <li><strong>A Kubernetes deployment that runs a Java process consuming a maximum of 1 gig of heap to operate optimally</strong></li>
  </ol>
  <p><em><strong>How can I safely maximise the amount of pods running on the two nodes while never having Kubernetes terminate my PODs because of memory limits?</strong></em></p>
  <pre><code>apiVersion: apps/v1
  kind: Deployment
  metadata:
    name: my-deployment
  spec:
    replicas: 1
    template:
      metadata:
        labels:
      app: my-deployment
      spec:
        containers:
        - name: my-deployment
      image: myreg:5000/my-deployment:0.0.1-SNAPSHOT
      ports:
      - containerPort: 8080
        name: http
      resources:
        requests:
          memory: 1024Mi
        limits:
          memory: 1024Mi
  </code></pre>
  <p>Java 8 update 131+ has a flag -XX:+UseCGroupMemoryLimitForHeap to use the Docker limits that come from the Kubernetes deployment.</p>
  <p><strong>My Docker experiments show me what is happening in Kubernetes</strong></p>
  <p><strong>If I run the following in Docker:</strong></p>
  <pre><code>docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -version
  </code></pre>
  <p><em><strong>I get:</strong></em></p>
  <pre><code>VM settings:
  Max. Heap Size (Estimated): 228.00M
  </code></pre>
  <p>This low value is because Java sets -XX:MaxRAMFraction to 4 by default and I get about 1/4 of the ram allocated...</p>
  <p><strong>If I run the same command with -XX:MaxRAMFraction=2 in Docker:</strong></p>
  <pre><code>docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=2 -version
  </code></pre>
  <p><em><strong>I get:</strong></em></p>
  <pre><code>VM settings:
  Max. Heap Size (Estimated): 455.50M
  </code></pre>
  <p>Finally setting MaxRAMFraction=1 quickly causes Kubernetes to Kill my container.</p>
  <pre><code>docker run -m 1024m anapsix/alpine-java:8_server-jre_unlimited java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XshowSettings:vm -XX:MaxRAMFraction=1 -version
  </code></pre>
  <p><em><strong>I get:</strong></em></p>
  <pre><code>VM settings:
  Max. Heap Size (Estimated): 910.50M
  </code></pre>