JDK-6724367 : par compact could clear less young gen summary data
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: 6
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2008-07-10
  • Updated: 2010-04-28
  • Resolved: 2010-04-28
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 6 JDK 7 Other
6u14Fixed 7Fixed hs14Fixed
The par compaction summary phase makes two passes over each Space in the GC heap.  The first pass updates the data as if each Space were to be compacted completely (i.e., leaving no dead space) into itself.  This is used to determine how much data is live in the Space and allows a dense prefix to be computed where applicable (the old gen and the perm gen).  The second pass then computes the final destinations.  Live data from the young gen Spaces is normally copied to the old gen, assuming it will fit.  For young gen spaces that fit into the old gen, certain fields of the summary data must be cleared.  More data than necessary is being cleared.

EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/2214b226b7f0

SUGGESTED FIX --- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp @@ -1635,7 +1635,7 @@ const size_t live = pointer_delta(_space_info[id].new_top(), space->bottom()); const size_t available = pointer_delta(target_space_end, *new_top_addr); - if (live <= available) { + if (live > 0 && live <= available) { // All the live data will fit. if (TraceParallelOldGCSummaryPhase) { tty->print_cr("summarizing %d into old_space @ " PTR_FORMAT, @@ -1645,16 +1645,18 @@ space->bottom(), space->top(), new_top_addr); - // Reset the new_top value for the space. - _space_info[id].set_new_top(space->bottom()); - // Clear the source_chunk field for each chunk in the space. + HeapWord* const new_top = _space_info[id].new_top(); + HeapWord* const clear_end = _summary_data.chunk_align_up(new_top); ChunkData* beg_chunk = _summary_data.addr_to_chunk_ptr(space->bottom()); - ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(space->top() - 1); - while (beg_chunk <= end_chunk) { + ChunkData* end_chunk = _summary_data.addr_to_chunk_ptr(clear_end); + while (beg_chunk < end_chunk) { beg_chunk->set_source_chunk(0); ++beg_chunk; } + + // Reset the new_top value for the space. + _space_info[id].set_new_top(space->bottom()); } }

EVALUATION The problem occurs only for Spaces in the young gen that are non-empty at the start of a full gc. Since -XX:+ScavengeBeforeFullGC is enabled by default, full GCs occur after a scavenge which normally empties eden. So 95% of the time, only To space contains data while Eden and From space are empty. For each non-empty space in the young gen, the summary phase currently clears data from space->bottom() to space->top() (the top() value before the start of the full gc). However, it is only necessary to clear from space->bottom() to the the "new top" for the space, where "new top" refers to the value computed by the first pass of the summary phase (which computes values to compact the space completely into itself). The "new top" is usually significantly less than space->top(), so less clearing can be done.