RFR: 8357449: ZGC: Multiple medium page sizes
Stefan Karlsson
stefank at openjdk.org
Thu May 22 09:42:54 UTC 2025
On Thu, 22 May 2025 06:32:04 GMT, Axel Boldt-Christmas <aboldtch at openjdk.org> wrote:
> <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 p...
Thanks for building this support! I did an initial pass through the patch and added some comments.
src/hotspot/share/gc/z/zGlobals.hpp line 46:
> 44: // Page size shifts
> 45: const size_t ZPageSizeSmallShift = ZGranuleSizeShift;
> 46: extern int ZPageSizeMediumShift;
Changing to int seems good, but this leaves an inconsistency with `ZPageSizeSmallShift`. I'd prefer if the type of that constant was also changed in this PR.
src/hotspot/share/gc/z/zHeuristics.cpp line 49:
> 47: // Enable medium pages
> 48: ZPageSizeMediumMax = size;
> 49: ZPageSizeMediumShift = log2i_exact(ZPageSizeMediumMax);
Is this an indication that `ZPageSizeMediumShift`should be named `ZPageSizeMediumMaxShift`
src/hotspot/share/gc/z/zPage.cpp line 47:
> 45: assert(!_virtual.is_null(), "Should not be null");
> 46: assert((_type == ZPageType::small && size() == ZPageSizeSmall) ||
> 47: (_type == ZPageType::medium && size() <= ZPageSizeMediumMax && size() >= ZPageSizeMediumMin) ||
Could we flip the order:
Suggestion:
(_type == ZPageType::medium && size() >= ZPageSizeMediumMin && size() <= ZPageSizeMediumMax) ||
Or, alternatively move the two range limits to the "outside" of the expression:
Suggestion:
(_type == ZPageType::medium && ZPageSizeMediumMin <= size() && size() <= ZPageSizeMediumMax) ||
or add a helper to check if a size is within the medium page range.
src/hotspot/share/gc/z/zRelocationSetSelector.cpp line 61:
> 59: bool ZRelocationSetSelectorGroup::is_disabled() {
> 60: // Medium pages are disabled when their page size is zero
> 61: return _page_type == ZPageType::medium && !ZPageSizeMediumEnabled;
The comment above described why the implementation looked like it did. Should it be updated?
src/hotspot/share/gc/z/zRelocationSetSelector.hpp line 82:
> 80: private:
> 81: static constexpr int NumPartitionsShift = 11;
> 82: static constexpr int NPartitions = int(1) << NumPartitionsShift;
Shenandoah shouldn't leak out unprefixed internal names. Let's fix that as a separate RFE.
src/hotspot/share/gc/z/z_globals.hpp line 108:
> 106: \
> 107: product(bool, ZUseMediumPageSizeRange, true, DIAGNOSTIC, \
> 108: "Allow multiple medium pages sizes") \
Maybe skip the s to match the flag ?
Suggestion:
"Allow multiple medium page sizes") \
-------------
PR Review: https://git.openjdk.org/jdk/pull/25381#pullrequestreview-2860438724
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102058013
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102062103
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102083430
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102094622
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102102690
PR Review Comment: https://git.openjdk.org/jdk/pull/25381#discussion_r2102108933
More information about the hotspot-gc-dev
mailing list