The Oracle docs say (emphasis mine):
For example, setting -XX:NewRatio=3 means that the ratio between the young and old generation is 1:3. In other words, the combined size of the eden and survivor spaces will be one-fourth of the total heap size.
The same was said here: What is the meaning of the -XX:NewRatio and -XX:OldSize JVM flags?
Thus, higher ratio makes Old Gen larger than Young Gen, not the opposite. However when checking on Java 17 with java -XX:MaxHeapSize=100M -XX:+PrintFlagsFinal -version
, I see that MaxNewSize
(Young Gen) gets 2/3 of the MaxHeapSize making it larger than Old Gen which is the opposite of what the docs say:
java -XX:MaxHeapSize=100M -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
size_t MaxHeapSize = 104857600 {product} {command line}
size_t MaxNewSize = 62914560 {product} {ergonomic}
uintx NewRatio = 2 {product} {default}
size_t SoftMaxHeapSize = 104857600 {manageable} {ergonomic}
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
Then I run the same command with Java 8 and get values aligned with the docs and common knowledge that I keep seeing on the Internet:
java -Xmx100M -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
uintx MaxHeapSize := 109051904 {product}
uintx MaxNewSize := 36175872 {product}
uintx NewRatio = 2 {product}
openjdk version "1.8.0_392"
OpenJDK Runtime Environment Corretto-8.392.08.1 (build 1.8.0_392-b08)
OpenJDK 64-Bit Server VM Corretto-8.392.08.1 (build 25.392-b08, mixed mode)
So, despite MaxHeapSize=100M
and default NewRatio=2
in both cases, MaxNewSize
is 62914560 in Java 17 and 36175872 in Java 8.
My question: what is happening? Is it a bug or has something changed but not reflected in the docs? Will appreciate any guidance to the right direction
EDIT: found out that if I specify NewRatio=2
explicitly, then Java 17 prints the expected result similar to Java 8:
java -XX:MaxHeapSize=100M -XX:NewRatio=2 -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
size_t MaxHeapSize = 104857600 {product} {command line}
size_t MaxNewSize = 34603008 {product} {ergonomic}
uintx NewRatio = 2 {product} {command line}
size_t SoftMaxHeapSize = 104857600 {manageable} {ergonomic}
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
Is this a bug or something with ergonomics that affects the values?
The Oracle docs say (emphasis mine):
For example, setting -XX:NewRatio=3 means that the ratio between the young and old generation is 1:3. In other words, the combined size of the eden and survivor spaces will be one-fourth of the total heap size.
The same was said here: What is the meaning of the -XX:NewRatio and -XX:OldSize JVM flags?
Thus, higher ratio makes Old Gen larger than Young Gen, not the opposite. However when checking on Java 17 with java -XX:MaxHeapSize=100M -XX:+PrintFlagsFinal -version
, I see that MaxNewSize
(Young Gen) gets 2/3 of the MaxHeapSize making it larger than Old Gen which is the opposite of what the docs say:
java -XX:MaxHeapSize=100M -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
size_t MaxHeapSize = 104857600 {product} {command line}
size_t MaxNewSize = 62914560 {product} {ergonomic}
uintx NewRatio = 2 {product} {default}
size_t SoftMaxHeapSize = 104857600 {manageable} {ergonomic}
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
Then I run the same command with Java 8 and get values aligned with the docs and common knowledge that I keep seeing on the Internet:
java -Xmx100M -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
uintx MaxHeapSize := 109051904 {product}
uintx MaxNewSize := 36175872 {product}
uintx NewRatio = 2 {product}
openjdk version "1.8.0_392"
OpenJDK Runtime Environment Corretto-8.392.08.1 (build 1.8.0_392-b08)
OpenJDK 64-Bit Server VM Corretto-8.392.08.1 (build 25.392-b08, mixed mode)
So, despite MaxHeapSize=100M
and default NewRatio=2
in both cases, MaxNewSize
is 62914560 in Java 17 and 36175872 in Java 8.
My question: what is happening? Is it a bug or has something changed but not reflected in the docs? Will appreciate any guidance to the right direction
EDIT: found out that if I specify NewRatio=2
explicitly, then Java 17 prints the expected result similar to Java 8:
java -XX:MaxHeapSize=100M -XX:NewRatio=2 -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxNewSize|NewRatio"
size_t MaxHeapSize = 104857600 {product} {command line}
size_t MaxNewSize = 34603008 {product} {ergonomic}
uintx NewRatio = 2 {product} {command line}
size_t SoftMaxHeapSize = 104857600 {manageable} {ergonomic}
openjdk version "17.0.2" 2022-01-18
OpenJDK Runtime Environment (build 17.0.2+8-86)
OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)
Is this a bug or something with ergonomics that affects the values?
Share Improve this question edited Feb 15 at 16:45 Turkhan Badalov asked Feb 15 at 15:58 Turkhan BadalovTurkhan Badalov 9241 gold badge11 silver badges19 bronze badges1 Answer
Reset to default 2You've missed the fact that JDK 17 defaults to G1 GC, whereas JDK 8 selects Parallel GC by default. If you set -XX:+UseG1GC
or -XX:+UseParallelGC
explicitly, the behavior will be the same both on JDK 8 and JDK 17.
Different GC algorithms indeed have different generation sizing policy. G1 uses adaptive sizing by default and it does not take NewRatio
into account unless the flag is set explicitly. Note that JVM has too many GC tunables, some of which contradict others. Generally, JVM favors flags that are set on the command line.