JDK-8067339 : PLAB reallocation might result in failure to allocate object in that recently allocated PLAB
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 9
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-12-12
  • Updated: 2015-11-09
  • Resolved: 2015-08-20
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9 b81Fixed
Related Reports
Relates :  
Description
During fixing of related problems I noticed that it is possible that when trying to allocate a new PLAB for a given allocation, the allocator algorithm may return a buffer that is too small for the object, resulting in premature evacuation failure.

The problem occurs because when allocating a new PLAB, not all memory is actually usable for allocation within the PLAB, but only the buffer size minus an alignment reserve.

This situation is asserted, so it seems to occur rarely (and is ignored in product mode).

Here is some commented code.

HeapWord* G1ParGCAllocator::allocate_slow(GCAllocPurpose purpose, size_t word_sz, AllocationContext_t context) {
  HeapWord* obj = NULL;
  size_t gclab_word_size = _g1h->desired_plab_sz(purpose);
  if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) {
    G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose, context);
    add_to_alloc_buffer_waste(alloc_buf->words_remaining());
    alloc_buf->retire(false /* end_of_gc */, false /* retain */);

    HeapWord* buf = _g1h->par_allocate_during_gc(purpose, gclab_word_size, context);

    ^^---- allocate a buffer of gclab_word_size

    if (buf == NULL) {
      return NULL; // Let caller handle allocation failure.
    }
    // Otherwise.
    alloc_buf->set_word_size(gclab_word_size);
    alloc_buf->set_buf(buf);

    obj = alloc_buf->allocate(word_sz);

   ^^---- try to allocate word_sz in the PLAB.  Since there actually is only plab_word_sz - ParGCAllocBuffer::AlignmentReserve space for allocation, allocation may actually fail.

    assert(obj != NULL, "buffer was definitely big enough...");
  } else {
    obj = _g1h->par_allocate_during_gc(purpose, word_sz, context);
  }
  return obj;
}
Comments
The problem does not seem to be as significant as expected. The worst thing that happens is either the object being prematurely promoted into the next gen, or in rare cases an evacuation failure because if the PLAB just allocated has been rather large, it might cause the code to not find space for the object at all.
17-08-2015