JDK-6977970 : CMS: concurrentMarkSweepGeneration.cpp:7947 assert(addr <= _limit) failed: sweep invariant
  • Type: Bug
  • Component: hotspot
  • Sub-Component: gc
  • Affected Version: hs19
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2010-08-18
  • Updated: 2011-04-23
  • Resolved: 2011-04-23
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.
Other JDK 6 JDK 7 Other
1.4.2_31,hs19Fixed 6u21pFixed 7Fixed hs19Fixed
Related Reports
Relates :  
Relates :  
Description
This is an old bug that was uncovered as a result of a change that went into
CR 6948538. The specific change was that since the product build used
-XX:-BlockOffsetArrayUseUnallocatedBlock, the fastdebug builds were also
changed (from trueInDebug to false) so that the same code paths were
exercised in both, so we were testing the product bits. This revealed
a long-standing bug in the code that tripped an assertion that was a tad
too strong. Note that the bug itself exists in the product builds preceding
6948538; it was just that the bug was not revealed until the recent change in the
setting of the flag for debug builds.

More specifically, the CMS sweep is limited to the high water mark (if any)
of allocation at the point at which the concurrent marking cycle was started.
When we do not use +BlockOffsetArrayUseUnallocatedBlock, this is the "end"
of the committed space for a CMS generation. If the CMS generation is not
fully committed at this point and is expanded during the sweep, then the
newly expanded portion is coalesced with the previously co-terminal chunk
in order to limit fragmentation. That means that a previously recorded
"limit" (being the address of the previous "end") is no longer a block
boundary and may not be encountered by the sweep, which may skip over that
specific address. This fell afoul of the code and assertion in question,
which is reproduced below:-

     7936 size_t SweepClosure::do_blk_careful(HeapWord* addr) {

     7937   FreeChunk* fc = (FreeChunk*)addr;

     7938   size_t res;

     7939 

     7940   // check if we are done sweepinrg

     7941   if (addr == _limit) { // we have swept up to the limit, do nothing more

     7942     assert(_limit >= _sp->bottom() && _limit <= _sp->end(),

     7943            "sweep _limit out of bounds");

     7944     // help the closure application finish

     7945     return pointer_delta(_sp->end(), _limit);

     7946   }

     7947   assert(addr <= _limit, "sweep invariant");


The fix is to relax the code to allow a "skipping over" the limit,
rather than "stepping on the limit", see suggested fix section.

Comments
EVALUATION http://hg.openjdk.java.net/jdk7/hotspot-gc/hotspot/rev/5ed703250bff
18-08-2010

EVALUATION See description, workaround and suggested fix sections.
18-08-2010

SUGGESTED FIX diff -r be3f9c242c9d src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Aug 16 15:58:42 2010 -0700 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Aug 17 23:59:47 2010 -0700 @@ -7938,13 +7938,13 @@ size_t SweepClosure::do_blk_careful(Heap size_t res; // check if we are done sweepinrg - if (addr == _limit) { // we have swept up to the limit, do nothing more + if (addr >= _limit) { // we have swept up to or past the limit, do nothing more assert(_limit >= _sp->bottom() && _limit <= _sp->end(), "sweep _limit out of bounds"); // help the closure application finish - return pointer_delta(_sp->end(), _limit); - } - assert(addr <= _limit, "sweep invariant"); + return pointer_delta(_sp->end(), addr); + } + assert(addr < _limit, "sweep invariant"); // check if we should yield do_yield_check(addr);
18-08-2010

WORK AROUND Fixing the CMS generation sizes (by setting initial/min/max to the same value), so as to prevent genetration expansion, will avoid the assertion:- -Xms<n> -Xmx<n> -XX:PermSize=<m> -XX:MaxPermSize=<m>
18-08-2010