Support jvm mem percentage (#3747)

This commit is contained in:
Leon Kampwerth
2025-11-06 13:37:23 +01:00
committed by GitHub
parent eeb62d45f9
commit 3941bd4e41
4 changed files with 76 additions and 18 deletions
+7 -13
View File
@@ -10,6 +10,12 @@ By default, the image declares an initial and maximum Java memory-heap limit of
The values of all three are passed directly to the JVM and support format/units as `<size>[g|G|m|M|k|K]`. The values of all three are passed directly to the JVM and support format/units as `<size>[g|G|m|M|k|K]`.
To have control over heap size, without relying on absolute memory sizes percentages are also supported using `<size>%`.
!!! info "RAMPercentage parameters"
Percentage based heap sizing is enabled using `-XX:InitialRAMPercentage` for `INIT_MEMORY` and `-XX:MaxRAMPercentage` for `MAX_MEMORY`.
For details on the function of these parameters look [here](https://www.baeldung.com/java-jvm-parameters-rampercentage).
!!! example "Using docker run" !!! example "Using docker run"
``` ```
@@ -37,19 +43,7 @@ The values of all three are passed directly to the JVM and support format/units
MAX_MEMORY: 4G MAX_MEMORY: 4G
``` ```
To let the JVM calculate the heap size from the container declared memory limit, unset `MEMORY` with an empty value, such as `-e MEMORY=""`. By default, the JVM will use 25% of the container memory limit as the heap limit; however, as an example the following would tell the JVM to use 75% of the container limit of 4GB of memory: To let the JVM calculate the heap size from the container declared memory limit, unset `MEMORY` with an empty value, such as `-e MEMORY=""`. By default, the JVM will use 25% of the container memory limit as the heap limit.
!!! example "MaxRAMPercentage using compose file"
```
environment:
MEMORY: ""
JVM_XX_OPTS: "-XX:MaxRAMPercentage=75"
deploy:
resources:
limits:
memory: 4G
```
!!! important !!! important
The settings above only set the Java **heap** limits. Memory resource requests and limits on the overall container should also account for non-heap memory usage. An extra 25% is [a general best practice](https://dzone.com/articles/best-practices-java-memory-arguments-for-container). The settings above only set the Java **heap** limits. Memory resource requests and limits on the overall container should also account for non-heap memory usage. An extra 25% is [a general best practice](https://dzone.com/articles/best-practices-java-memory-arguments-for-container).
+13 -1
View File
@@ -28,7 +28,19 @@ function buildSpigotFromSource {
mkdir ${tempDir} mkdir ${tempDir}
cd ${tempDir} cd ${tempDir}
jvmOpts="-Xms${INIT_MEMORY:-$MEMORY} -Xmx${MAX_MEMORY:-$MEMORY}" jvmOpts=""
if isPercentage "${INIT_MEMORY:-$MEMORY}"; then
jvmOpts+="-XX:InitialRAMPercentage=$(getPercentageValue "${INIT_MEMORY:-$MEMORY}") "
else
jvmOpts+="-Xms${INIT_MEMORY:-$MEMORY} "
fi
if isPercentage "${MAX_MEMORY:-$MEMORY}"; then
jvmOpts+="-XX:MaxRAMPercentage=$(getPercentageValue "${MAX_MEMORY:-$MEMORY}")"
else
jvmOpts+="-Xmx${MAX_MEMORY:-$MEMORY}"
fi
logn '' logn ''
curl -sSL -o ${tempDir}/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar && \ curl -sSL -o ${tempDir}/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar && \
+27 -3
View File
@@ -368,10 +368,15 @@ fi
if [[ ${INIT_MEMORY} || ${MAX_MEMORY} ]]; then if [[ ${INIT_MEMORY} || ${MAX_MEMORY} ]]; then
log "Setting initial memory to ${INIT_MEMORY:=${MEMORY}} and max to ${MAX_MEMORY:=${MEMORY}}" log "Setting initial memory to ${INIT_MEMORY:=${MEMORY}} and max to ${MAX_MEMORY:=${MEMORY}}"
if [[ ${INIT_MEMORY} ]]; then if isPercentage "$INIT_MEMORY"; then
JVM_OPTS="-XX:InitialRAMPercentage=$(getPercentageValue "${INIT_MEMORY}") ${JVM_OPTS}"
elif [[ ${INIT_MEMORY} ]]; then
JVM_OPTS="-Xms${INIT_MEMORY} ${JVM_OPTS}" JVM_OPTS="-Xms${INIT_MEMORY} ${JVM_OPTS}"
fi fi
if [[ ${MAX_MEMORY} ]]; then
if isPercentage "$MAX_MEMORY"; then
JVM_OPTS="-XX:MaxRAMPercentage=$(getPercentageValue "${MAX_MEMORY}") ${JVM_OPTS}"
elif [[ ${MAX_MEMORY} ]]; then
JVM_OPTS="-Xmx${MAX_MEMORY} ${JVM_OPTS}" JVM_OPTS="-Xmx${MAX_MEMORY} ${JVM_OPTS}"
fi fi
fi fi
@@ -431,15 +436,34 @@ elif [[ ${TYPE} == "CURSEFORGE" ]]; then
copyFilesForCurseForge copyFilesForCurseForge
if isPercentage "$INIT_MEMORY" || isPercentage "$MAX_MEMORY"; then
# Convert to bytes
NORM_INIT_MEM=$(normalizeMemSize "$INIT_MEMORY")
NORM_MAX_MEM=$(normalizeMemSize "$MAX_MEMORY")
# Convert to MB
((NORM_INIT_MEM*=1048576))
((NORM_MAX_MEM*=1048576))
cat > "${FTB_DIR}/settings-local.sh" <<EOF
export MIN_RAM="${NORM_INIT_MEM}M"
export MAX_RAM="${NORM_MAX_MEM}M"
export JAVA_PARAMETERS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts"
EOF
else
cat > "${FTB_DIR}/settings-local.sh" <<EOF cat > "${FTB_DIR}/settings-local.sh" <<EOF
export MIN_RAM="${INIT_MEMORY}" export MIN_RAM="${INIT_MEMORY}"
export MAX_RAM="${MAX_MEMORY}" export MAX_RAM="${MAX_MEMORY}"
export JAVA_PARAMETERS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts" export JAVA_PARAMETERS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts"
EOF EOF
fi
# patch CurseForge cfg file, if present # patch CurseForge cfg file, if present
if [ -f "${FTB_DIR}/settings.cfg" ] && [[ ${MAX_MEMORY} ]]; then if [ -f "${FTB_DIR}/settings.cfg" ] && [[ ${MAX_MEMORY} ]]; then
sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${MAX_MEMORY}/" "${FTB_DIR}/settings.cfg" if isPercentage "$MAX_MEMORY"; then
sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${NORM_MAX_MEM}M/" "${FTB_DIR}/settings.cfg"
else
sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${MAX_MEMORY}/" "${FTB_DIR}/settings.cfg"
fi
fi fi
cd "${FTB_DIR}" || (logError "Can't go into ${FTB_DIR}"; exit 1) cd "${FTB_DIR}" || (logError "Can't go into ${FTB_DIR}"; exit 1)
+29 -1
View File
@@ -39,6 +39,23 @@ function get_major_version() {
echo "$version" | cut -d. -f 1-2 echo "$version" | cut -d. -f 1-2
} }
function isPercentage() {
local value=$1
[[ $value =~ ^[0-9]+(\.[0-9]+)?\s*%$ ]]
}
function getPercentageValue() {
local value=$1
if [[ "$value" =~ ^([0-9]+(\.[0-9]+)?)\s*%$ ]]; then
echo "${BASH_REMATCH[1]}"
return 0
else
logError "Value '$value' is not a valid percentage."
return 1
fi
}
function isURL() { function isURL() {
local value=$1 local value=$1
@@ -229,6 +246,7 @@ function logRcon() {
function normalizeMemSize() { function normalizeMemSize() {
local scale=1 local scale=1
local mem=1
case ${1,,} in case ${1,,} in
*k) *k)
scale=1024 scale=1024
@@ -239,10 +257,20 @@ function normalizeMemSize() {
*g) *g)
scale=1073741824 scale=1073741824
;; ;;
*%)
# Get system memory
if [ -f "/sys/fs/cgroup/memory/memory.limit_in_bytes" ]; then
mem=$( cat /sys/fs/cgroup/memory/memory.limit_in_bytes )
elif [ -f "/sys/fs/cgroup/memory.max" ]; then
mem=$( cat /sys/fs/cgroup/memory.max )
fi
# Scale is used to transform percentages into decimals (eg. 60 -> 0.6)
scale=0.01
;;
esac esac
val=${1:0:-1} val=${1:0:-1}
echo $((val * scale)) echo $((val * scale * mem))
} }
function compare_version() { function compare_version() {