United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6977970 CMS: concurrentMarkSweepGeneration.cpp:7947 assert(addr <= _limit) failed: sweep invariant
JDK-6977970 : CMS: concurrentMarkSweepGeneration.cpp:7947 assert(addr <= _limit) failed: sweep invariant

Details
Type:
Bug
Submit Date:
2010-08-18
Status:
Closed
Updated Date:
2011-04-23
Project Name:
JDK
Resolved Date:
2011-04-23
Component:
hotspot
OS:
generic
Sub-Component:
gc
CPU:
generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
hs19
Fixed Versions:
hs19 (b06)

Related Reports
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Relates:
Relates:
Relates:

Sub Tasks

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

See description, workaround and suggested fix sections.
                                     
2010-08-18
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>
                                     
2010-08-18
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);
                                     
2010-08-18
EVALUATION

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



Hardware and Software, Engineered to Work Together