matrei commented on code in PR #16545: URL: https://github.com/apache/grails-core/pull/16545#discussion_r4198528764
########## grails-doc/src/en/guide/deployment/deploymentTasks.adoc: ########## @@ -70,6 +70,58 @@ Heap is only part of total memory: allow space for metaspace, code cache, direct A container can be killed for exceeding its limit even if the Java heap has not run out of memory. Measure resident memory and GC behavior under load rather than copying a fixed heap percentage between applications. +[[java25-memory]] +=== Java 25 Memory Considerations Review Comment: The new subsection is inserted in the middle of "Memory, storage, and logging". Everything after it in that section (`JAVA_TOOL_OPTIONS`/`JAVA_OPTS`, buildpacks, logging, storage, heap dumps, debug interfaces) now renders under the "Java 25 Memory Considerations" heading. Could you move it to the end of the section, just before `== Graceful shutdown and rolling updates`? ########## grails-doc/src/en/guide/deployment/deploymentTasks.adoc: ########## @@ -70,6 +70,58 @@ Heap is only part of total memory: allow space for metaspace, code cache, direct A container can be killed for exceeding its limit even if the Java heap has not run out of memory. Measure resident memory and GC behavior under load rather than copying a fixed heap percentage between applications. +[[java25-memory]] +=== Java 25 Memory Considerations + +Java 25 uses more off-heap memory than earlier LTS releases. +The most significant change is that the metaspace — the native memory region that holds class metadata — is now **unbounded by default**. +On earlier JDKs the initial metaspace high-water mark was approximately 12 MB; on Java 25 there is no upper limit unless you set one explicitly. +A Grails application that loads many classes (plugins, Hibernate mappings, GSP-compiled views) can therefore consume substantially more native memory than the same application on Java 21. Review Comment: > the metaspace … is now **unbounded by default**. On earlier JDKs the initial metaspace high-water mark was approximately 12 MB; on Java 25 there is no upper limit See the review summary: `MaxMetaspaceSize` is unlimited by default on 8+ ([JDK 25 `java` reference](https://docs.oracle.com/en/java/javase/25/docs/specs/man/java.html): "By default, the size isn't limited"), and `MetaspaceSize` (~21 MB on 17/21/25) is a GC trigger, not a limit. The same applies to "Java 25 uses more off-heap memory than earlier LTS releases": do we have a source or measurement for that? ########## grails-doc/src/en/guide/deployment/deploymentTasks.adoc: ########## @@ -70,6 +70,58 @@ Heap is only part of total memory: allow space for metaspace, code cache, direct A container can be killed for exceeding its limit even if the Java heap has not run out of memory. Measure resident memory and GC behavior under load rather than copying a fixed heap percentage between applications. +[[java25-memory]] +=== Java 25 Memory Considerations + +Java 25 uses more off-heap memory than earlier LTS releases. +The most significant change is that the metaspace — the native memory region that holds class metadata — is now **unbounded by default**. +On earlier JDKs the initial metaspace high-water mark was approximately 12 MB; on Java 25 there is no upper limit unless you set one explicitly. +A Grails application that loads many classes (plugins, Hibernate mappings, GSP-compiled views) can therefore consume substantially more native memory than the same application on Java 21. + +In a container environment this matters most: the JVM heap limit (`-Xmx` or `-XX:MaxRAMPercentage`) does not cover metaspace, so a container sized only for the heap can be killed by the container runtime's OOM killer when metaspace grows beyond the remaining native memory budget. + +**Recommended settings for Java 25:** + +Set an explicit metaspace ceiling so the JVM raises `OutOfMemoryError: Metaspace` before the container runtime kills the process: + +[source,bash] +---- +java -Xmx512m -XX:MaxMetaspaceSize=256m -Dgrails.env=prod -jar application.jar +---- + +Or, using percentage-based heap sizing in a container: + +[source,bash] +---- +java -XX:MaxRAMPercentage=60.0 -XX:MaxMetaspaceSize=256m -Dgrails.env=prod -jar application.jar +---- + +Tune `-XX:MaxMetaspaceSize` from a measured baseline: run the application under representative load, observe the metaspace usage with `jcmd <pid> VM.metaspace` or a monitoring agent, and add a safety margin. +A typical Grails application with Hibernate and a moderate number of plugins stabilizes between 128 MB and 256 MB of metaspace; a large application with many plugins may need more. + +If you also want to control how aggressively the JVM reclaims unused metaspace after a GC cycle, set the free-ratio bounds: + +[source,bash] +---- +-XX:MinMetaspaceFreeRatio=20 -XX:MaxMetaspaceFreeRatio=80 Review Comment: > control how aggressively the JVM reclaims unused metaspace These flags set the headroom around the metaspace GC threshold after a collection. The example also doesn't match the description: the defaults are 40/70, so `MaxMetaspaceFreeRatio=80` makes the JVM shrink *less* aggressively, and `MinMetaspaceFreeRatio=20` leaves less headroom, which means more frequent metaspace-triggered GCs. Without a concrete reason to tune them, I'd suggest removing this block. ########## grails-doc/src/en/guide/deployment/deploymentStandalone.adoc: ########## @@ -45,6 +45,7 @@ java -Xmx768m -Dgrails.env=prod -jar build/libs/myapp-0.1.jar \ This example requires `/etc/myapp/` to exist. Place external `application.yml` or `application.properties` there. Size the heap for your workload and leave memory for metaspace, thread stacks, direct buffers, native libraries, and the operating system. +On Java 25, metaspace is unbounded by default; see <<java25-memory,Java 25 Memory Considerations>> for recommended settings. Review Comment: > On Java 25, metaspace is unbounded by default Same issue: this is true on every JDK since 8 ([JDK 8 `java` reference](https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.html): "By default, the size is not limited"). Something like "Metaspace is unbounded by default; see <<…>> for recommended settings." would work. ########## grails-doc/src/en/guide/upgrading/upgrading80x.adoc: ########## @@ -4716,3 +4716,42 @@ for template renders: Objects passed with `bean` or `collection` are not part of `model`. See link:theWebLayer.html#definingInterceptors[Defining Interceptors]. + +[[java25-memory-upgrade]] +==== 85. Java 25 Memory Requirements Review Comment: - This mostly repeats the deployment section, so the same factual issues apply here. The `UseCompressedClassPointers` bullets could also mention that the flag becomes obsolete (ignored) in JDK 27 ([JDK-8363996](https://github.com/openjdk/jdk/commit/da296cbea1)). I'd shorten the upgrade note to the actionable bits (consider setting `MaxMetaspaceSize`; remove `UseCompressedClassPointers`) and link to the deployment guide for the rest. - "Grails 8 supports Java 25 (the next LTS after Java 21)": this might fit better next to "1. Java 21 Minimum Requirement" than at the end as item 85. - Cross-chapter link: elsewhere this file links into other chapters with `link:<chapter>.html#<anchor>[...]` (e.g. `link:theWebLayer.html#definingInterceptors`). Could you confirm `<<java25-memory,...>>` resolves in the multi-page guide, or switch to `link:deployment.html#java25-memory[...]`? ########## grails-doc/src/en/guide/deployment/deploymentTasks.adoc: ########## @@ -70,6 +70,58 @@ Heap is only part of total memory: allow space for metaspace, code cache, direct A container can be killed for exceeding its limit even if the Java heap has not run out of memory. Measure resident memory and GC behavior under load rather than copying a fixed heap percentage between applications. +[[java25-memory]] +=== Java 25 Memory Considerations + +Java 25 uses more off-heap memory than earlier LTS releases. +The most significant change is that the metaspace — the native memory region that holds class metadata — is now **unbounded by default**. +On earlier JDKs the initial metaspace high-water mark was approximately 12 MB; on Java 25 there is no upper limit unless you set one explicitly. +A Grails application that loads many classes (plugins, Hibernate mappings, GSP-compiled views) can therefore consume substantially more native memory than the same application on Java 21. + +In a container environment this matters most: the JVM heap limit (`-Xmx` or `-XX:MaxRAMPercentage`) does not cover metaspace, so a container sized only for the heap can be killed by the container runtime's OOM killer when metaspace grows beyond the remaining native memory budget. + +**Recommended settings for Java 25:** + +Set an explicit metaspace ceiling so the JVM raises `OutOfMemoryError: Metaspace` before the container runtime kills the process: + +[source,bash] +---- +java -Xmx512m -XX:MaxMetaspaceSize=256m -Dgrails.env=prod -jar application.jar +---- + +Or, using percentage-based heap sizing in a container: + +[source,bash] +---- +java -XX:MaxRAMPercentage=60.0 -XX:MaxMetaspaceSize=256m -Dgrails.env=prod -jar application.jar +---- + +Tune `-XX:MaxMetaspaceSize` from a measured baseline: run the application under representative load, observe the metaspace usage with `jcmd <pid> VM.metaspace` or a monitoring agent, and add a safety margin. +A typical Grails application with Hibernate and a moderate number of plugins stabilizes between 128 MB and 256 MB of metaspace; a large application with many plugins may need more. Review Comment: > A typical Grails application with Hibernate and a moderate number of plugins stabilizes between 128 MB and 256 MB of metaspace Where does this range come from? If it isn't measured, I'd drop the numbers and keep the "measure under load and add a margin" guidance. Readers will copy the `256m` cap, and an app that needs more will fail with `OutOfMemoryError: Metaspace` at runtime. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
