When I'm establishing the memory limits (-Xmx512m -Xms512m) in the deployment.yml for a Spring Boot Application which the docker image was generated with the command (mvn spring-boot:build-image) then I'm receiving the following error:
Setting Active Processor Count to 4
Adding $JAVA_OPTS to $JAVA_TOOL_OPTIONS
unable to calculate memory configuration
all memory regions require 1130933K which is greater than 956052K available for allocation:
-Xmx512M, 0 headroom, -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=94645K, -XX:ReservedCodeCacheSize=240M,
-Xss1M * 250 threads ←[31;1mERROR: ←[0mfailed to launch: exec.d: failed to execute exec.d file
at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1
Current deployment.yml config:
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: JAVA_OPTS
value: >-
-XX: PrintGCDetails
-Xlog:gc
-XX: UseParallelGC
-XX: PrintFlagsFinal
-Xmx512m
-Xms512m
resources:
requests:
cpu: 1554m
memory: 979M
limits:
cpu: 1554m
memory: 979M
How to set the memory limits properly or disable the buildpack memory calculator?
NOTE: I'm using JAVA 11.
CodePudding user response:
You're getting the error:
all memory regions require 1130933K which is greater than 956052K available for allocation:
-Xmx512M, 0 headroom, -XX:MaxDirectMemorySize=10M, -XX:MaxMetaspaceSize=94645K, -XX:ReservedCodeCacheSize=240M,
-Xss1M * 250 threads
which is telling you that you have an invalid memory configuration. The amount of memory that you want to assign to the JVM does not fit within the limits you have put on your container.
There are a number of ways you can fix this:
Increase the container memory limit so that the JVM fits. The error message tells you how much you'd need,
1130933K
.Reduce the amount of memory you're assigning to the JVM so that it fits within the container memory limit. The error message tells you which JVM memory settings are being used, you can override them in
JAVA_TOOL_OPTIONS
(orJAVA_OPTS
, anything added there is included withinJAVA_TOOL_OPTIONS
) to limit them.Remove
-Xmx512m -Xms512m
from JAVA_OPTS and just let the memory calculator generate the largest JVM memory configuration that will fit within the container memory limit you've assigned. You won't get that much heap, but you'll get as large of a heap as possible within the given container memory limit.
Some notes on these options:
If you try option #2, be careful in terms of what you reduce. The JVM is memory-hungry, but that's also how it's so fast. Make sure you are performance testing before and after any changes you make to ensure that you're not hurting your application performance (or to confirm that you're still performing to required levels).
With the Paketo Java buildpack, you should really never set
-Xmx
and-Xms
. What you want to do instead is to adjust the other memory settings, like-Xss
,-XX:ReservedCodeCacheSize=240M
,-XX:MaxDirectMemorySize=10M
, thread count, etc...The memory calculator will adjust the
-Xmx
and-Xms
settings dynamically so that they consume the remainder of the memory in the container. If you manually set these values, what's likely to happen is that you will either cause an error because the values are too large (what happened here) or that you set them too low and the JVM is not using all of the memory available to it. Let the memory calculator do its job and you'll get the optimal settings.There is no option to disable the memory calculator and I would strongly caution against attempting to do that. The memory calculator is your friend here.
It's like a compiler for JVM memory settings. It is checking and validating the settings you enter, so it can tell you in advance if there is a problem with your memory configuration. It might be annoying that it complains, but this is far, far better than having your container crash in the middle of the night because it runs out of memory. If it complains, adjust your memory configuration and then rest easy knowing that everything is properly sized to fit in your container.
The memory calculator will by default size your application for a production deployment, optimizing for performance, not low-memory consumption. Again, Java trades higher memory consumption for speed. To do this, it means your container needs at least 1G of RAM.
There is a Paketo RFC to add a low-memory mode to the memory calculator. This would make it easier to run PoC applications and other low-traffic apps that are willing to accept potentially lower performance in exchange for reducing memory consumption (and thereby cost). This RFC has not been implemented as of this post, but we hope to have it implemented in the near future.
CodePudding user response:
Thank you for your answer. But I applied the second option, I understood your point of view, I will try to do a summary about the approach
Iteration 1: No limits
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: JAVA_OPTS
value: >-
-Xlog:gc
-XX: UseParallelGC
Memory Calculator:
Calculating JVM memory based on 13287832K available memory
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx12681764K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 13287832K, Thread Count: 250, Loaded Class Count: 14194, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX: ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -Xlog:gc -XX: UseParallelGC -XX:MaxDirectMemorySize=10M -Xmx12681764K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M -XX: UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX: PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enable=true
Xmx12681764K = 1585,2205 MB
In this case, Graphana visualize all resources from the hardware and it is not the ideal configuration so, it is necessary to define limits from the upper boundary, the pod.
Iteration 2: With defined limits at kubernetes level
env:
- name: SPRING_PROFILES_ACTIVE
value: prod
- name: JAVA_OPTS
value: >-
-Xlog:gc
-XX: UseParallelGC
resources:
requests:
cpu: 1554m
memory: 979M
limits:
cpu: 1554m
memory: 979M
Memory calculator:
Calculated JVM Memory Configuration: -XX:MaxDirectMemorySize=10M -Xmx349984K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M (Total Memory: 956052K, Thread Count: 250, Loaded Class Count: 14194, Headroom: 0%)
Enabling Java Native Memory Tracking
Adding 128 container CA certificates to JVM truststore
Spring Cloud Bindings Enabled
Picked up JAVA_TOOL_OPTIONS: -Djava.security.properties=/layers/paketo-buildpacks_bellsoft-liberica/java-security-properties/java-security.properties -XX: ExitOnOutOfMemoryError -XX:ActiveProcessorCount=4 -Xlog:gc -XX: UseParallelGC -XX:MaxDirectMemorySize=10M -Xmx349984K -XX:MaxMetaspaceSize=94067K -XX:ReservedCodeCacheSize=240M -Xss1M -XX: UnlockDiagnosticVMOptions -XX:NativeMemoryTracking=summary -XX: PrintNMTStatistics -Dorg.springframework.cloud.bindings.boot.enabl
In this case, Memory Calculator determinates a minimum memory to operate with the application but not limit the upper boundary because it is limited by the configuration from k8s level. My doubt was generated by the delay in the grahana visualization.
As you say, Memory calculator is our side to help.
Many thanks in advance
Alberto.