matrei commented on code in PR #16545:
URL: https://github.com/apache/grails-core/pull/16545#discussion_r4422656173
##########
grails-doc/src/en/guide/deployment/deploymentTasks.adoc:
##########
@@ -80,6 +80,46 @@ Configure writable paths explicitly when using a read-only
root filesystem.
Heap dumps and other diagnostics need a writable destination with sufficient
space and controlled access.
Keep JVM debugging and management interfaces private; they should not be
exposed through the application's public ingress.
+[[java25-memory]]
+=== Java 25 Metaspace and Off-Heap Memory
Review Comment:
With that sentence gone, the only Java 25-specific part of this section is
the `UseCompressedClassPointers` note. Everything else applies to Java 21 too,
and someone on 21 who reads "Recommended settings for Java 25:" (line 89) will
assume it doesn't apply to them. I'd drop "Java 25" here and on line 89, and
change the link text in `deploymentStandalone.adoc:48` to match. The
`java25-memory` anchor can stay.
```suggestion
=== Metaspace and Off-Heap Memory
```
##########
grails-doc/src/en/guide/upgrading/upgrading80x.adoc:
##########
@@ -4837,3 +4837,39 @@ With `DISCRIMINATOR` multi-tenancy, GORM for MongoDB,
GORM for Neo4j and GORM's
* Without a current tenant, these methods throw `TenantNotFoundException`, as
a query does. `getAll` without ids still returns an empty list.
* Inside `Tenants.withoutId { }` a lookup by id is still not restricted to a
tenant, and neither is a proxy returned by `load` or `proxy` that is
initialized there. As the previous note says, only `withoutId` lifts the
restriction: a tenant id of `default` restricts a lookup by id to that tenant
as it restricts a query.
* A lookup by id still finds an instance that the session holds for the
current tenant, including one that has been saved but not flushed, and it does
not flush the session.
+
+
+[[java25-memory-upgrade]]
+==== 88. Java 25 Memory Requirements
Review Comment:
8.0.x now has `==== 88. Lookups by id are restricted to the current tenant
with DISCRIMINATOR multi-tenancy`. Git merges the two without a conflict, so
it's easy to miss, but after a rebase on 8.0.x this one needs to be 89.
```suggestion
==== 89. Java 25 Memory Requirements
```
Optional: "Requirements" reads as if Java 25 needs more memory, which the
section itself says isn't the case. Something like "Metaspace and Compressed
Class Pointers on Java 25" would describe what's in it.
##########
grails-doc/src/en/guide/upgrading/upgrading80x.adoc:
##########
@@ -4837,3 +4837,39 @@ With `DISCRIMINATOR` multi-tenancy, GORM for MongoDB,
GORM for Neo4j and GORM's
* Without a current tenant, these methods throw `TenantNotFoundException`, as
a query does. `getAll` without ids still returns an empty list.
* Inside `Tenants.withoutId { }` a lookup by id is still not restricted to a
tenant, and neither is a proxy returned by `load` or `proxy` that is
initialized there. As the previous note says, only `withoutId` lifts the
restriction: a tenant id of `default` restricts a lookup by id to that tenant
as it restricts a query.
* A lookup by id still finds an instance that the session holds for the
current tenant, including one that has been saved but not flushed, and it does
not flush the session.
+
+
+[[java25-memory-upgrade]]
+==== 88. Java 25 Memory Requirements
+
+Grails 8 supports Java 25 (the next LTS after Java 21).
Review Comment:
Nit: section 1 says this now (line 57), so it can go here. Also on line 57:
the rest of the file puts one sentence per line.
```suggestion
```
##########
grails-doc/src/en/guide/upgrading/upgrading80x.adoc:
##########
@@ -4837,3 +4837,39 @@ With `DISCRIMINATOR` multi-tenancy, GORM for MongoDB,
GORM for Neo4j and GORM's
* Without a current tenant, these methods throw `TenantNotFoundException`, as
a query does. `getAll` without ids still returns an empty list.
* Inside `Tenants.withoutId { }` a lookup by id is still not restricted to a
tenant, and neither is a proxy returned by `load` or `proxy` that is
initialized there. As the previous note says, only `withoutId` lifts the
restriction: a tenant id of `default` restricts a lookup by id to that tenant
as it restricts a query.
* A lookup by id still finds an instance that the session holds for the
current tenant, including one that has been saved but not flushed, and it does
not flush the session.
+
+
+[[java25-memory-upgrade]]
+==== 88. Java 25 Memory Requirements
+
+Grails 8 supports Java 25 (the next LTS after Java 21).
+Both Java 21 and Java 25 leave metaspace unlimited by default unless you set
an explicit ceiling with `-XX:MaxMetaspaceSize`; this default has been
unchanged since JDK 8.
+On both versions, `-XX:MetaspaceSize` sets the initial high-water mark that
triggers garbage collection, not a limit on metaspace growth. The JVM adjusts
this threshold according to metadata usage.
+
+A Grails application loads a large number of classes — plugins, Hibernate
entity mappings, GSP-compiled views, Spring beans — so metaspace can account
for a significant part of the process's native memory on either JDK.
+In a container environment this is especially important: the 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.
+
+**What to do when running on Java 25:**
+
+Set an explicit metaspace ceiling with `-XX:MaxMetaspaceSize` 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 metaspace usage with `jcmd <pid>
VM.metaspace`, and add a safety margin.
+
+The `-XX:+/-UseCompressedClassPointers` flag is deprecated in Java 25 and will
be removed in a future release.
+
+* If your startup scripts pass `-XX:+UseCompressedClassPointers`, remove it
because it is the default.
+* If they pass `-XX:-UseCompressedClassPointers` to disable compressed class
pointers, note that dropping it changes the memory layout and has to be checked
against the measured class-space use.
Review Comment:
> will be removed in a future release
The deployment note already says when: JDK-8363996 makes the flag obsolete
in JDK 27, where it is accepted with a warning and ignored. That matters most
for the minus form. From 27 the VM always uses compressed class pointers, so
the class-space check in the second bullet is needed whether or not someone
drops the flag. Something like:
```suggestion
The `-XX:+/-UseCompressedClassPointers` flag is deprecated in Java 25 and
becomes obsolete in JDK 27
(https://github.com/openjdk/jdk/commit/da296cbea1[JDK-8363996]), where it is
accepted with a warning and ignored.
* If your startup scripts pass `-XX:+UseCompressedClassPointers`, remove it
because it is the default.
* If they pass `-XX:-UseCompressedClassPointers` to disable compressed class
pointers, check the class-space use that `jcmd <pid> VM.metaspace` reports
before you drop it.
Dropping it changes the memory layout, and from JDK 27 compressed class
pointers are always on, whether or not the flag is there.
```
##########
grails-doc/src/en/guide/upgrading/upgrading80x.adoc:
##########
@@ -4837,3 +4837,39 @@ With `DISCRIMINATOR` multi-tenancy, GORM for MongoDB,
GORM for Neo4j and GORM's
* Without a current tenant, these methods throw `TenantNotFoundException`, as
a query does. `getAll` without ids still returns an empty list.
* Inside `Tenants.withoutId { }` a lookup by id is still not restricted to a
tenant, and neither is a proxy returned by `load` or `proxy` that is
initialized there. As the previous note says, only `withoutId` lifts the
restriction: a tenant id of `default` restricts a lookup by id to that tenant
as it restricts a query.
* A lookup by id still finds an instance that the session holds for the
current tenant, including one that has been saved but not flushed, and it does
not flush the session.
+
+
+[[java25-memory-upgrade]]
+==== 88. Java 25 Memory Requirements
+
+Grails 8 supports Java 25 (the next LTS after Java 21).
+Both Java 21 and Java 25 leave metaspace unlimited by default unless you set
an explicit ceiling with `-XX:MaxMetaspaceSize`; this default has been
unchanged since JDK 8.
+On both versions, `-XX:MetaspaceSize` sets the initial high-water mark that
triggers garbage collection, not a limit on metaspace growth. The JVM adjusts
this threshold according to metadata usage.
+
+A Grails application loads a large number of classes — plugins, Hibernate
entity mappings, GSP-compiled views, Spring beans — so metaspace can account
for a significant part of the process's native memory on either JDK.
+In a container environment this is especially important: the 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.
+
+**What to do when running on Java 25:**
+
+Set an explicit metaspace ceiling with `-XX:MaxMetaspaceSize` 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 metaspace usage with `jcmd <pid>
VM.metaspace`, and add a safety margin.
+
+The `-XX:+/-UseCompressedClassPointers` flag is deprecated in Java 25 and will
be removed in a future release.
+
+* If your startup scripts pass `-XX:+UseCompressedClassPointers`, remove it
because it is the default.
+* If they pass `-XX:-UseCompressedClassPointers` to disable compressed class
pointers, note that dropping it changes the memory layout and has to be checked
against the measured class-space use.
+
+See <<java25-memory,Java 25 Memory Considerations>> in the deployment guide
for full details, including systemd service unit examples and guidance on the
metaspace free-ratio flags.
Review Comment:
> including systemd service unit examples and guidance on the metaspace
free-ratio flags
The free-ratio guidance was removed in the first round (I mentioned this
line last time too), and the link text is the heading from two rounds ago.
On my question from the first round: `<<java25-memory,…>>` does resolve on
the chapter pages, because `DocPublisher.linkAcrossChapters` rewrites
cross-chapter fragment links, so this form is fine.
```suggestion
See <<java25-memory,Metaspace and Off-Heap Memory>> in the deployment guide
for full details, including a systemd service unit example.
```
(If the heading keeps "Java 25", use that as the link text instead.)
##########
grails-doc/src/en/guide/deployment/deploymentTasks.adoc:
##########
@@ -80,6 +80,46 @@ Configure writable paths explicitly when using a read-only
root filesystem.
Heap dumps and other diagnostics need a writable destination with sufficient
space and controlled access.
Keep JVM debugging and management interfaces private; they should not be
exposed through the application's public ingress.
+[[java25-memory]]
+=== Java 25 Metaspace and Off-Heap Memory
+
+Java 25 uses more off-heap memory than earlier LTS releases. Metaspace has no
upper limit by default (MaxMetaspaceSize is unlimited on every JDK since 8).
Grails applications load many classes (plugins, Hibernate mappings,
GSP-compiled views), so metaspace can make up a large part of the process's
native memory.
Review Comment:
> Java 25 uses more off-heap memory than earlier LTS releases.
I asked about a source for this in both earlier rounds and haven't seen one.
The upgrade note in this PR now says Java 21 and Java 25 behave the same for
metaspace, so the two pages contradict each other. Unless there's a measurement
or a JDK release note behind it, please remove it. The suggestion also adds
backticks around `MaxMetaspaceSize` and puts one sentence per line, like the
rest of the file:
```suggestion
Metaspace has no upper limit by default (`MaxMetaspaceSize` is unlimited on
every JDK since 8).
Grails applications load many classes (plugins, Hibernate mappings,
GSP-compiled views), so metaspace can make up a large part of the process's
native memory.
```
--
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]