提交 a7b138c3 编写于 作者: Y ysr

7008136: CMS: assert((HeapWord*)nextChunk <= _limit) failed: sweep invariant

Summary: The recorded _sweep_limit may not necessarily remain a block boundary as the old generation expands during a concurrent cycle. Terminal actions inside the sweep closure need to be aware of this as they cross over the limit.
Reviewed-by: johnc, minqi
上级 79988060
...@@ -7881,25 +7881,23 @@ SweepClosure::SweepClosure(CMSCollector* collector, ...@@ -7881,25 +7881,23 @@ SweepClosure::SweepClosure(CMSCollector* collector,
} }
// We need this destructor to reclaim any space at the end // We need this destructor to reclaim any space at the end
// of the space, which do_blk below may not have added back to // of the space, which do_blk below may not yet have added back to
// the free lists. [basically dealing with the "fringe effect"] // the free lists.
SweepClosure::~SweepClosure() { SweepClosure::~SweepClosure() {
assert_lock_strong(_freelistLock); assert_lock_strong(_freelistLock);
// this should be treated as the end of a free run if any assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
// The current free range should be returned to the free lists "sweep _limit out of bounds");
// as one coalesced chunk. // Flush any remaining coterminal free run as a single
// coalesced chunk to the appropriate free list.
if (inFreeRange()) { if (inFreeRange()) {
flushCurFreeChunk(freeFinger(), assert(freeFinger() < _limit, "freeFinger points too high");
pointer_delta(_limit, freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(_limit, freeFinger()));
assert(freeFinger() < _limit, "the finger pointeth off base");
if (CMSTraceSweeper) { if (CMSTraceSweeper) {
gclog_or_tty->print("destructor:"); gclog_or_tty->print("Sweep: last chunk: ");
gclog_or_tty->print("Sweep:put_free_blk 0x%x ("SIZE_FORMAT") " gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") [coalesced:"SIZE_FORMAT"]\n",
"[coalesced:"SIZE_FORMAT"]\n", freeFinger(), pointer_delta(_limit, freeFinger()), lastFreeRangeCoalesced());
freeFinger(), pointer_delta(_limit, freeFinger()),
lastFreeRangeCoalesced());
} }
} } // else nothing to flush
NOT_PRODUCT( NOT_PRODUCT(
if (Verbose && PrintGC) { if (Verbose && PrintGC) {
gclog_or_tty->print("Collected "SIZE_FORMAT" objects, " gclog_or_tty->print("Collected "SIZE_FORMAT" objects, "
...@@ -7936,9 +7934,8 @@ SweepClosure::~SweepClosure() { ...@@ -7936,9 +7934,8 @@ SweepClosure::~SweepClosure() {
void SweepClosure::initialize_free_range(HeapWord* freeFinger, void SweepClosure::initialize_free_range(HeapWord* freeFinger,
bool freeRangeInFreeLists) { bool freeRangeInFreeLists) {
if (CMSTraceSweeper) { if (CMSTraceSweeper) {
gclog_or_tty->print("---- Start free range 0x%x with free block [%d] (%d)\n", gclog_or_tty->print("---- Start free range at 0x%x with free block (%d)\n",
freeFinger, _sp->block_size(freeFinger), freeFinger, freeRangeInFreeLists);
freeRangeInFreeLists);
} }
assert(!inFreeRange(), "Trampling existing free range"); assert(!inFreeRange(), "Trampling existing free range");
set_inFreeRange(true); set_inFreeRange(true);
...@@ -7993,21 +7990,36 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { ...@@ -7993,21 +7990,36 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
// may have caused us to coalesce the block ending at the address _limit // may have caused us to coalesce the block ending at the address _limit
// with a newly expanded chunk (this happens when _limit was set to the // with a newly expanded chunk (this happens when _limit was set to the
// previous _end of the space), so we may have stepped past _limit; see CR 6977970. // previous _end of the space), so we may have stepped past _limit; see CR 6977970.
if (addr >= _limit) { // we have swept up to or past the limit, do nothing more if (addr >= _limit) { // we have swept up to or past the limit: finish up
assert(_limit >= _sp->bottom() && _limit <= _sp->end(), assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
"sweep _limit out of bounds"); "sweep _limit out of bounds");
assert(addr < _sp->end(), "addr out of bounds"); assert(addr < _sp->end(), "addr out of bounds");
// help the closure application finish // Flush any remaining coterminal free run as a single
// coalesced chunk to the appropriate free list.
if (inFreeRange()) {
assert(freeFinger() < _limit, "finger points too high");
flush_cur_free_chunk(freeFinger(),
pointer_delta(addr, freeFinger()));
if (CMSTraceSweeper) {
gclog_or_tty->print("Sweep: last chunk: ");
gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") "
"[coalesced:"SIZE_FORMAT"]\n",
freeFinger(), pointer_delta(addr, freeFinger()),
lastFreeRangeCoalesced());
}
}
// help the iterator loop finish
return pointer_delta(_sp->end(), addr); return pointer_delta(_sp->end(), addr);
} }
assert(addr < _limit, "sweep invariant");
assert(addr < _limit, "sweep invariant");
// check if we should yield // check if we should yield
do_yield_check(addr); do_yield_check(addr);
if (fc->isFree()) { if (fc->isFree()) {
// Chunk that is already free // Chunk that is already free
res = fc->size(); res = fc->size();
doAlreadyFreeChunk(fc); do_already_free_chunk(fc);
debug_only(_sp->verifyFreeLists()); debug_only(_sp->verifyFreeLists());
assert(res == fc->size(), "Don't expect the size to change"); assert(res == fc->size(), "Don't expect the size to change");
NOT_PRODUCT( NOT_PRODUCT(
...@@ -8017,7 +8029,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { ...@@ -8017,7 +8029,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
NOT_PRODUCT(_last_fc = fc;) NOT_PRODUCT(_last_fc = fc;)
} else if (!_bitMap->isMarked(addr)) { } else if (!_bitMap->isMarked(addr)) {
// Chunk is fresh garbage // Chunk is fresh garbage
res = doGarbageChunk(fc); res = do_garbage_chunk(fc);
debug_only(_sp->verifyFreeLists()); debug_only(_sp->verifyFreeLists());
NOT_PRODUCT( NOT_PRODUCT(
_numObjectsFreed++; _numObjectsFreed++;
...@@ -8025,7 +8037,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { ...@@ -8025,7 +8037,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
) )
} else { } else {
// Chunk that is alive. // Chunk that is alive.
res = doLiveChunk(fc); res = do_live_chunk(fc);
debug_only(_sp->verifyFreeLists()); debug_only(_sp->verifyFreeLists());
NOT_PRODUCT( NOT_PRODUCT(
_numObjectsLive++; _numObjectsLive++;
...@@ -8078,7 +8090,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) { ...@@ -8078,7 +8090,7 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
// to a free list which may be overpopulated. // to a free list which may be overpopulated.
// //
void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
size_t size = fc->size(); size_t size = fc->size();
// Chunks that cannot be coalesced are not in the // Chunks that cannot be coalesced are not in the
// free lists. // free lists.
...@@ -8094,22 +8106,20 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { ...@@ -8094,22 +8106,20 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) {
// addr and purported end of this block. // addr and purported end of this block.
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
// Some chunks cannot be coalesced in under any circumstances. // Some chunks cannot be coalesced under any circumstances.
// See the definition of cantCoalesce(). // See the definition of cantCoalesce().
if (!fc->cantCoalesce()) { if (!fc->cantCoalesce()) {
// This chunk can potentially be coalesced. // This chunk can potentially be coalesced.
if (_sp->adaptive_freelists()) { if (_sp->adaptive_freelists()) {
// All the work is done in // All the work is done in
doPostIsFreeOrGarbageChunk(fc, size); do_post_free_or_garbage_chunk(fc, size);
} else { // Not adaptive free lists } else { // Not adaptive free lists
// this is a free chunk that can potentially be coalesced by the sweeper; // this is a free chunk that can potentially be coalesced by the sweeper;
if (!inFreeRange()) { if (!inFreeRange()) {
// if the next chunk is a free block that can't be coalesced // if the next chunk is a free block that can't be coalesced
// it doesn't make sense to remove this chunk from the free lists // it doesn't make sense to remove this chunk from the free lists
FreeChunk* nextChunk = (FreeChunk*)(addr + size); FreeChunk* nextChunk = (FreeChunk*)(addr + size);
assert((HeapWord*)nextChunk <= _limit, "sweep invariant"); if (nextChunk->isFree() && // The next chunk is free...
if ((HeapWord*)nextChunk < _limit && // there's a next chunk...
nextChunk->isFree() && // which is free...
nextChunk->cantCoalesce()) { // ... but cant be coalesced nextChunk->cantCoalesce()) { // ... but cant be coalesced
// nothing to do // nothing to do
} else { } else {
...@@ -8156,14 +8166,14 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { ...@@ -8156,14 +8166,14 @@ void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) {
// as the end of a free run if any // as the end of a free run if any
if (inFreeRange()) { if (inFreeRange()) {
// we kicked some butt; time to pick up the garbage // we kicked some butt; time to pick up the garbage
assert(freeFinger() < addr, "the finger pointeth off base"); assert(freeFinger() < addr, "freeFinger points too high");
flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
} }
// else, nothing to do, just continue // else, nothing to do, just continue
} }
} }
size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
// This is a chunk of garbage. It is not in any free list. // This is a chunk of garbage. It is not in any free list.
// Add it to a free list or let it possibly be coalesced into // Add it to a free list or let it possibly be coalesced into
// a larger chunk. // a larger chunk.
...@@ -8175,7 +8185,7 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { ...@@ -8175,7 +8185,7 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) {
// addr and purported end of just dead object. // addr and purported end of just dead object.
_bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
doPostIsFreeOrGarbageChunk(fc, size); do_post_free_or_garbage_chunk(fc, size);
} else { } else {
if (!inFreeRange()) { if (!inFreeRange()) {
// start of a new free range // start of a new free range
...@@ -8214,35 +8224,16 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { ...@@ -8214,35 +8224,16 @@ size_t SweepClosure::doGarbageChunk(FreeChunk* fc) {
return size; return size;
} }
size_t SweepClosure::doLiveChunk(FreeChunk* fc) { size_t SweepClosure::do_live_chunk(FreeChunk* fc) {
HeapWord* addr = (HeapWord*) fc; HeapWord* addr = (HeapWord*) fc;
// The sweeper has just found a live object. Return any accumulated // The sweeper has just found a live object. Return any accumulated
// left hand chunk to the free lists. // left hand chunk to the free lists.
if (inFreeRange()) { if (inFreeRange()) {
if (_sp->adaptive_freelists()) { assert(freeFinger() < addr, "freeFinger points too high");
flushCurFreeChunk(freeFinger(), flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
pointer_delta(addr, freeFinger()));
} else { // not adaptive freelists
set_inFreeRange(false);
// Add the free range back to the free list if it is not already
// there.
if (!freeRangeInFreeLists()) {
assert(freeFinger() < addr, "the finger pointeth off base");
if (CMSTraceSweeper) {
gclog_or_tty->print("Sweep:put_free_blk 0x%x (%d) "
"[coalesced:%d]\n",
freeFinger(), pointer_delta(addr, freeFinger()),
lastFreeRangeCoalesced());
}
_sp->addChunkAndRepairOffsetTable(freeFinger(),
pointer_delta(addr, freeFinger()), lastFreeRangeCoalesced());
}
}
} }
// Common code path for original and adaptive free lists. // This object is live: we'd normally expect this to be
// this object is live: we'd normally expect this to be
// an oop, and like to assert the following: // an oop, and like to assert the following:
// assert(oop(addr)->is_oop(), "live block should be an oop"); // assert(oop(addr)->is_oop(), "live block should be an oop");
// However, as we commented above, this may be an object whose // However, as we commented above, this may be an object whose
...@@ -8257,7 +8248,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { ...@@ -8257,7 +8248,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) {
assert(size == CompactibleFreeListSpace::adjustObjectSize(size), assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
"alignment problem"); "alignment problem");
#ifdef DEBUG #ifdef DEBUG
if (oop(addr)->klass_or_null() != NULL && if (oop(addr)->klass_or_null() != NULL &&
( !_collector->should_unload_classes() ( !_collector->should_unload_classes()
|| (oop(addr)->is_parsable()) && || (oop(addr)->is_parsable()) &&
...@@ -8271,7 +8262,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { ...@@ -8271,7 +8262,7 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) {
CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()), CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()),
"P-mark and computed size do not agree"); "P-mark and computed size do not agree");
} }
#endif #endif
} else { } else {
// This should be an initialized object that's alive. // This should be an initialized object that's alive.
...@@ -8298,19 +8289,17 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) { ...@@ -8298,19 +8289,17 @@ size_t SweepClosure::doLiveChunk(FreeChunk* fc) {
return size; return size;
} }
void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc, void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
size_t chunkSize) { size_t chunkSize) {
// doPostIsFreeOrGarbageChunk() should only be called in the smart allocation // do_post_free_or_garbage_chunk() should only be called in the case
// scheme. // of the adaptive free list allocator.
bool fcInFreeLists = fc->isFree(); bool fcInFreeLists = fc->isFree();
assert(_sp->adaptive_freelists(), "Should only be used in this case."); assert(_sp->adaptive_freelists(), "Should only be used in this case.");
assert((HeapWord*)fc <= _limit, "sweep invariant"); assert((HeapWord*)fc <= _limit, "sweep invariant");
if (CMSTestInFreeList && fcInFreeLists) { if (CMSTestInFreeList && fcInFreeLists) {
assert(_sp->verifyChunkInFreeLists(fc), assert(_sp->verifyChunkInFreeLists(fc), "free chunk is not in free lists");
"free chunk is not in free lists");
} }
if (CMSTraceSweeper) { if (CMSTraceSweeper) {
gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize); gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize);
} }
...@@ -8382,20 +8371,21 @@ void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc, ...@@ -8382,20 +8371,21 @@ void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc,
if (inFreeRange()) { if (inFreeRange()) {
// In a free range but cannot coalesce with the right hand chunk. // In a free range but cannot coalesce with the right hand chunk.
// Put the current free range into the free lists. // Put the current free range into the free lists.
flushCurFreeChunk(freeFinger(), flush_cur_free_chunk(freeFinger(),
pointer_delta(addr, freeFinger())); pointer_delta(addr, freeFinger()));
} }
// Set up for new free range. Pass along whether the right hand // Set up for new free range. Pass along whether the right hand
// chunk is in the free lists. // chunk is in the free lists.
initialize_free_range((HeapWord*)fc, fcInFreeLists); initialize_free_range((HeapWord*)fc, fcInFreeLists);
} }
} }
void SweepClosure::flushCurFreeChunk(HeapWord* chunk, size_t size) {
void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) {
assert(inFreeRange(), "Should only be called if currently in a free range."); assert(inFreeRange(), "Should only be called if currently in a free range.");
assert(size > 0, assert(size > 0,
"A zero sized chunk cannot be added to the free lists."); "A zero sized chunk cannot be added to the free lists.");
if (!freeRangeInFreeLists()) { if (!freeRangeInFreeLists()) {
if(CMSTestInFreeList) { if (CMSTestInFreeList) {
FreeChunk* fc = (FreeChunk*) chunk; FreeChunk* fc = (FreeChunk*) chunk;
fc->setSize(size); fc->setSize(size);
assert(!_sp->verifyChunkInFreeLists(fc), assert(!_sp->verifyChunkInFreeLists(fc),
...@@ -8430,7 +8420,7 @@ void SweepClosure::do_yield_work(HeapWord* addr) { ...@@ -8430,7 +8420,7 @@ void SweepClosure::do_yield_work(HeapWord* addr) {
// chunk just flushed, they will need to wait for the next // chunk just flushed, they will need to wait for the next
// sweep to be coalesced. // sweep to be coalesced.
if (inFreeRange()) { if (inFreeRange()) {
flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
} }
// First give up the locks, then yield, then re-lock. // First give up the locks, then yield, then re-lock.
......
...@@ -1701,7 +1701,9 @@ class SweepClosure: public BlkClosureCareful { ...@@ -1701,7 +1701,9 @@ class SweepClosure: public BlkClosureCareful {
CMSCollector* _collector; // collector doing the work CMSCollector* _collector; // collector doing the work
ConcurrentMarkSweepGeneration* _g; // Generation being swept ConcurrentMarkSweepGeneration* _g; // Generation being swept
CompactibleFreeListSpace* _sp; // Space being swept CompactibleFreeListSpace* _sp; // Space being swept
HeapWord* _limit; HeapWord* _limit;// the address at which the sweep should stop because
// we do not expect blocks eligible for sweeping past
// that address.
Mutex* _freelistLock; // Free list lock (in space) Mutex* _freelistLock; // Free list lock (in space)
CMSBitMap* _bitMap; // Marking bit map (in CMSBitMap* _bitMap; // Marking bit map (in
// generation) // generation)
...@@ -1745,14 +1747,13 @@ class SweepClosure: public BlkClosureCareful { ...@@ -1745,14 +1747,13 @@ class SweepClosure: public BlkClosureCareful {
private: private:
// Code that is common to a free chunk or garbage when // Code that is common to a free chunk or garbage when
// encountered during sweeping. // encountered during sweeping.
void doPostIsFreeOrGarbageChunk(FreeChunk *fc, void do_post_free_or_garbage_chunk(FreeChunk *fc, size_t chunkSize);
size_t chunkSize);
// Process a free chunk during sweeping. // Process a free chunk during sweeping.
void doAlreadyFreeChunk(FreeChunk *fc); void do_already_free_chunk(FreeChunk *fc);
// Process a garbage chunk during sweeping. // Process a garbage chunk during sweeping.
size_t doGarbageChunk(FreeChunk *fc); size_t do_garbage_chunk(FreeChunk *fc);
// Process a live chunk during sweeping. // Process a live chunk during sweeping.
size_t doLiveChunk(FreeChunk* fc); size_t do_live_chunk(FreeChunk* fc);
// Accessors. // Accessors.
HeapWord* freeFinger() const { return _freeFinger; } HeapWord* freeFinger() const { return _freeFinger; }
...@@ -1769,7 +1770,7 @@ class SweepClosure: public BlkClosureCareful { ...@@ -1769,7 +1770,7 @@ class SweepClosure: public BlkClosureCareful {
// Initialize a free range. // Initialize a free range.
void initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists); void initialize_free_range(HeapWord* freeFinger, bool freeRangeInFreeLists);
// Return this chunk to the free lists. // Return this chunk to the free lists.
void flushCurFreeChunk(HeapWord* chunk, size_t size); void flush_cur_free_chunk(HeapWord* chunk, size_t size);
// Check if we should yield and do so when necessary. // Check if we should yield and do so when necessary.
inline void do_yield_check(HeapWord* addr); inline void do_yield_check(HeapWord* addr);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册