RFR: 8256390: ZGC: Relocate in-place instead of having a heap reserve

Stefan Karlsson stefank at openjdk.java.net
Tue Nov 17 09:55:09 UTC 2020

On Mon, 16 Nov 2020 13:45:51 GMT, Per Liden <pliden at openjdk.org> wrote:

> The heap reserve is a portion of the heap that is set aside to cope with “emergency situations”, like when ZGC needs to compact the heap when it’s already full. However, due to a number of factors (mutator relocation, page pinning, etc) there is no guarantee that relocation will always succeed. In fact, we can end up in situations where we fail to reclaim memory even when 90% of the heap is garbage (JDK-8254346 is an example of where this happens).
> So, even if the heap reserve serves its purpose well in most cases, it still doesn't offer any guarantees that relocation succeeds in all cases. To get the guarantees we want we could, instead of having a heap reserve, turn to doing in-place relocation. In other words, if a worker fails to allocate a new page, then it compacts the page currently being relocated, and then use that page as the target for new allocations. In addition, if a mutator fails to relocate an object, then it waits for a worker to relocate the object, instead of pinning the page. This patch does exactly that, and hence makes ZGC more resilient in situations where memory is scares. It also means that ZGC works even better when using small heap (where memory tends to be scares).
> Testing: Tier1-7 on linux-x64, Tier-1-3 on all Oracle platforms, 50+ runs of gc-test-suite on linux-x64 (both with and without `-XX:+ZStressRelocateInPlace`).

First pass looking through the patch

src/hotspot/share/gc/z/zRelocate.cpp line 144:

> 142:     }
> 143: 
> 144:     // Failed to relocate obejct. Wait for a worker thread to

obejct -> object

src/hotspot/share/gc/z/zForwarding.cpp line 52:

> 50: bool ZForwarding::retain_page() {
> 51:   for (;;) {
> 52:     const int32_t ref_count = Atomic::load(&_ref_count);

I think this might have to be load_acquire to "aquire" the forwarding table entry write.

src/hotspot/share/gc/z/zForwarding.cpp line 195:

> 193:   // Verify number of live objects and bytes
> 194:   _page->verify_live_objects(live_objects);
> 195:   _page->verify_live_bytes(live_bytes);

Maybe one function?:
`_page->verify_live(live_objects, live_bytes)`

src/hotspot/share/gc/z/zHeap.inline.hpp line 118:

> 116: 
> 117:   // Forward object
> 118:   return _relocate.forward_object(forwarding, ZAddress::good(addr));

Does this remove the last usage of zForwarding.inline.hpp in this file?

src/hotspot/share/gc/z/zPageAllocator.cpp line 264:

> 262: size_t ZPageAllocator::unused() const {
> 263:   const ZPageAllocatorStats st = stats();
> 264:   return st.capacity() - st.used() - st.claimed();

Used by JVM_FreeMemory. I'd prefer if that usage was kept lock free.

src/hotspot/share/gc/z/zPageAllocator.cpp line 750:

> 748: 
> 749:     // Record flushed pages as claimed
> 750:     _claimed += flushed;

See FreeMemory comment above.


Changes requested by stefank (Reviewer).

PR: https://git.openjdk.java.net/jdk/pull/1228

More information about the hotspot-gc-dev mailing list