JDK-8353837 : Trim InitialRAMPercentage to improve startup in default modes
  • Type: CSR
  • Component: hotspot
  • Sub-Component: gc
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 26
  • Submitted: 2025-04-07
  • Updated: 2025-09-02
  • Resolved: 2025-09-02
Related Reports
CSR :  
Description
Summary
-------

Trim the default setting for `InitialRAMPercentage` to `0.2%` to better match current hardware memory sizes for Java applications running with default heap sizes.

Problem
-------

When user does not supply `-Xms`, GC ergonomics guesses the initial heap size, based on `InitialRAMPercentage` (IRAMP), currently set at 1/64 of physical RAM. The 1/64 guess had not changed since the initial load in 2007. This guess made sense back then. Unfortunately, real machines of today come with lots of physical memory, which drives the default initial heap size very high.

The initial heap size drives the startup times, because GCs need to initialize their internal data structures, e.g. remsets, card tables, or even heap memory itself for the initial heap. In worst cases, this adds single-digit millisecond overhead for Serial/Parallel, double-digit millisecond overheads for G1, multi-second overheads for ZGC during the startup. See the RFE for sample performance data.

Solution
--------

Trim the default setting for `InitialRAMPercentage` to `0.2%` to better match current memory configurations. This looks like a sweet spot for current configurations:

 - On huge 1024G machine, this yields 2G initial heap
 - On reasonably sized 128G machine, this gives 256M initial heap
 - On smaller 1G container, this gives 2M initial heap

Depending on heap sizing policy a given GC implements, this may cause more GCs to resize the heap to the same "stable" level as before. This is likely not a problem for small out-of-the-box applications that this enhancement targets.

We expect that the impact of this change on long-running applications would be much lower. Most, if not all memory conscious applications set `-Xms` explicitly. In that case, `IRAMP` setting yields to `Xms`.

Specification
-------------

See the associated PR:

```
diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp
index ba29daf2fe1..924c45f137d 100644
--- a/src/hotspot/share/gc/shared/gc_globals.hpp
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp
@@ -288,7 +288,7 @@
           "size on systems with small physical memory size")                \
           range(0.0, 100.0)                                                 \
                                                                             \
-  product(double, InitialRAMPercentage, 1.5625,                             \
+  product(double, InitialRAMPercentage, 0.2,                                \
           "Percentage of real memory used for initial heap size")           \
           range(0.0, 100.0)                                                 \
                                                                             \
```
Comments
Moving to Approved for JDK 26; I see a release note is already in progress.
02-09-2025

Release Note: https://bugs.openjdk.org/browse/JDK-8366690
02-09-2025

Thank you, Erik! I have now Finalized the CSR.
02-09-2025

Seems reasonable!
29-08-2025

Still looking for reviewers! Please put yourself as reviewer, so we can go ahead with this one.
26-08-2025

Friendly reminder: no takers for putting down a CSR review? :)
20-05-2025

As Erik says, ZGC is running in its own problems with too large initial heap size, which will enjoy smaller initial heap size, but it is not the target we have for this improvement. My intent is to optimize double-digit milliseconds for shorter applications running with Serial/Parallel/G1. Ultimately, users that just run `java MyApp.java` should not be paying this cost unconditionally. True, this cost would have to be paid at some point later, when GC would need to resize the heap. That said, that cost might not be ever paid for a short-running applications. For long-running applications, our standing recommendation right now is to explicitly set the min/max heap sizes. This recommendation would likely persist until we have full AHS implemented everywhere. I think we should go forward with this trim. I see no objections for 0.2% as the new target, so let's go with that. Process: I think we go with one-phase CSR process, so I need formal Reviews (Edit -> Reviewed-by) before I move this CSR to Finalized.
12-05-2025

Having said that, the existing initial heap size heuristics do appear to be quite weird to me. By default, the max heap size is set to 25% of the machine, but caps out at the 32 GB compressed oops limit. The initial heap size is also a fraction of the machine memory, but is bounded by the max heap size. That seems to imply that the fraction of the heap that gets primed is a function of the machine size; with a large enough machine, the entire heap is committed upfront. Not entirely sure what the reasoning is there, but it feels sort of strange to me. Haven't thought a lot about it though.
09-04-2025

Looking at the problem domain, you mention results you got across various GCs. The one that stands out to most obviously have a startup problem is ZGC. This is indeed entirely true and matches my experience well. But that's also one of the reasons why I have been working on automatic heap sizing for ZGC (cf. https://openjdk.org/jeps/8329758). In the automatic heap sizing work, the default minimum and initial heap size is now down at 2 MB, which is the minimum heap size ZGC can run on at all. The rest of the work of committing and paging in (and indeed also upgrading memory to use large pages) is all done by a concurrent thread. This pretty much removes the startup vs warmup problem when using ZGC; you get the best of both worlds. The app starts running instantly and warmup costs are paid for with concurrent threads to take the GC warmup noise to a rather silent level, especially compared to the other fun JVM warmup disco we got going early on. In summary, while ZGC has the biggest startup memory priming problem today, it is also about to have the smallest memory priming startup problem "soon". This makes me wonder if perhaps we should consider the impact on the other GCs instead, as motivation for this change of defaults, as the impact on ZGC is bound to be rather temporary. If I understand the numbers right, it seems to boil down to improving on double digit startup milliseconds. The cost is paid during warmup if the application eventually needs to use that heap memory we no longer commit up-front. That impact is harder to quantify, I suppose.
09-04-2025

> multi-second overheads for ZGC during the startup. For those that are curious about this, this happens because when committing memory via shared memory the OS faults in memory up-front. So, there's sort-of like running with -XX:+AlwaysPreTouch. You take the initial hit during startup instead of taking a latency hit during runtime.
08-04-2025

I think this would need a good release note.
07-04-2025

Just a side note. I recently observed some odd behavior with ParallelGC when facing a small initial heap size and optimizing for footprint (https://mail.openjdk.org/pipermail/hotspot-gc-dev/2024-November/050146.html). I think that is a bug that just should be fixed, so it is not an argument against this CSR. That said, the proposal sounds absolutely reasonable.
07-04-2025

Note: I have explored putting caps on `IRAMP` here: https://github.com/openjdk/jdk/pull/23262#issuecomment-2701763566 -- and I think it creates more problems than it solves. So I would prefer us to just trim the default without doing anything else.
07-04-2025