RFR: 8357449: ZGC: Multiple medium page sizes

Axel Boldt-Christmas aboldtch at openjdk.org
Thu May 22 06:36:14 UTC 2025


<details><summary><b>Background</b> (expandable section)</summary>
ZGC uses three different types of memory regions (Small, Medium and Large) as a compromise between memory waste and relocation induced latencies.

The allocated object size dictates which type of memory region it ends up in. These sizes are selected such that when an object allocation fails in a memory region because that object does not fit, the waste (unused bytes at the end) is at most 1/8th or 12.5%. This property is held for both the small and medium memory regions.

Objects larger than medium object allocation gets placed in a large memory region, which only ever contains one object. And because all memory region sizes are multiples of 2M, we end up with a memory waste which is the difference between object size rounded up to the nearest multiple of 2M and the exact object size.

For max heaps (Xmx) smaller than 1GB we use reduced medium memory region sizes at the cost of worse waste guarantees for large object allocation.

But for max heaps 1GB or larger our current selected medium memory region size is 32M. This results in a max medium object size of 4M (32M * 12.5%), which is the max size we want an application thread to have to relocate. So we end up with a guarantee that the waste in large memory regions is at most 33%.

A problem with medium pages is that they may cause allocation induced latencies. To reduce allocation latencies we track (cache) memory of memory regions which has been freed by the GC, so it can be reused for new memory regions used for allocations.

For small memory regions, as long as there is cached memory, it can use it, because the size of a small memory region (2M) is always a multiple of any other memory region that has been freed.

However for medium memory regions it may be that there is enough memory available in the cache, but it is only split into regions smaller than the medium memory regions size (32M). Currently this requires the allocating thread to remap multiple of these small memory regions into a new larger one, which involves calls into the operating system.

In ZGC we call our memory regions pages or zpages.
</details>

### Proposal
Allow for medium pages to have multiple sizes. Specifically allow all power of two sizes between the smallest size that can contain one medium object and the max medium page size. For a max medium page size of 32M the sizes ends up being {4M, 8M, 16M, 32M}.

And adds a "fast" medium page allocation path in the page allocator, which only claims memory from the cache, where the memory can directly satisfy one of these sizes. This will only fail if the cache is empty, or if all the memory is spread out in 2M segments. Then change the object allocator to use this for when mutator threads allocate or relocate objects. Reducing the probability that allocation or mutator relocation sees latencies induced by the page allocation.

GC relocation workers still allocate only the largest medium page size, and has the GC take the cost remapping memory. This way we can reduce mutator latencies at the cost of potential temporary increased memory waste.

The change from a fixed to variable size for medium pages requires some adaptation in relocation set selection. Earlier we simply used to compare live bytes sizes as a proxy for fragmentation, using pre-calculated values to avoid integer division and double arithmetic in the selection loop. I did something similar in ae2fa92f9356e2966726cc17f3e5d911be8b1f8e. May be a pre mature optimisation.

Also apparently we have a `NumPartitions` define in the codebase so had to name the constant differently. (I could probably move it to the .cpp file as well.)
https://github.com/openjdk/jdk/blob/f7619fd700ec6498948e5e84e8051be145683940/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp#L44

#### Testing

* All ZGC test tasks tier1-tier8 on all Oracle supported platforms
* All ZGC test tasks tier1-tier8 on linux-x64,linux-x64-debug with `-XX:+ZStressFastMediumPageAllocation`

Ran performance testing on an earlier baseline,
Re-running performance testing on latest rebase

-------------

Commit messages:
 - NumPartitions is reserved by Shenandoah
 - Add ZStressFastMediumPageAllocation
 - Add TestZMediumPageSizes
 - Optimized pre-filter
 - Multi-sized medium allocations

Changes: https://git.openjdk.org/jdk/pull/25381/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=25381&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8357449
  Stats: 392 lines in 19 files changed: 340 ins; 10 del; 42 mod
  Patch: https://git.openjdk.org/jdk/pull/25381.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/25381/head:pull/25381

PR: https://git.openjdk.org/jdk/pull/25381


More information about the hotspot-gc-dev mailing list