# HG changeset patch # User kbarrett # Date 1427676588 14400 # Sun Mar 29 20:49:48 2015 -0400 # Node ID bdc7ba6e567c96ec2e7898488918c7847da9eb0c # Parent 103eda5de0acbc8d19efe64fe90a768feb46291e [mq]: filter diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp @@ -3404,22 +3404,29 @@ } #endif -void CMTask::scan_object(oop obj) { +template +inline void CMTask::process_grey_object(oop obj) { + assert(scan || obj->is_typeArray(), "Skipping scan of grey non-typeArray"); assert(_nextMarkBitMap->isMarked((HeapWord*) obj), "invariant"); if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] we're scanning object "PTR_FORMAT, + gclog_or_tty->print_cr("[%u] processing grey object " PTR_FORMAT, _worker_id, p2i((void*) obj)); } size_t obj_size = obj->size(); _words_scanned += obj_size; - obj->oop_iterate(_cm_oop_closure); + if (scan) { + obj->oop_iterate(_cm_oop_closure); + } statsOnly( ++_objs_scanned ); check_limits(); } +template void CMTask::process_grey_object(oop); +template void CMTask::process_grey_object(oop); + // Closure for iteration over bitmaps class CMBitMapClosure : public BitMapClosure { private: diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp @@ -1099,6 +1099,8 @@ void regular_clock_call(); bool concurrent() { return _concurrent; } + template void process_grey_object(oop obj); + public: // It resets the task; it should be called right at the beginning of // a marking phase. @@ -1151,7 +1153,7 @@ inline void deal_with_reference(oop obj); // It scans an object and visits its children. - void scan_object(oop obj); + void scan_object(oop obj) { process_grey_object(obj); } // It pushes an object on the local queue. inline void push(oop obj); diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp +++ b/src/share/vm/gc_implementation/g1/concurrentMark.inline.hpp @@ -297,16 +297,30 @@ // CAS done in CMBitMap::parMark() call in the routine above. HeapWord* global_finger = _cm->finger(); -#if _CHECK_BOTH_FINGERS_ - // we will check both the local and global fingers - - if (_finger != NULL && objAddr < _finger) { - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the local finger ("PTR_FORMAT"), " - "pushing it", _worker_id, p2i(_finger)); + if (_CHECK_BOTH_FINGERS_ && _finger != NULL && objAddr < _finger) { + if (obj->is_typeArray()) { + // Immediately process arrays of binary data, rather + // than pushing on the mark stack. This keeps us from + // adding humongous objects to the mark stack that might + // be reclaimed before the entry is processed - see + // G1EagerReclaimHumongousPreSnapshotTypeArrays. The + // cost of the additional type test is mitigated by + // avoiding a trip through the mark stack, and by only + // doing bookkeeping update and avoiding the actual scan + // of the object - a typeArray contains no references, + // and the metadata is built-in. + process_grey_object(obj); + } else { + if (_cm->verbose_high()) { + gclog_or_tty->print_cr( + "[%u] below the local finger (" PTR_FORMAT "), pushing " PTR_FORMAT, + _worker_id, p2i(_finger), p2i(objAddr)); + } + push(obj); } - push(obj); - } else if (_curr_region != NULL && objAddr < _region_limit) { + } else if (_CHECK_BOTH_FINGERS_ && + _curr_region != NULL && + objAddr < _region_limit) { // do nothing } else if (objAddr < global_finger) { // Notice that the global finger might be moving forward @@ -318,29 +332,20 @@ // be pushed on the stack. So, some duplicate work, but no // correctness problems. - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); + if (obj->is_typeArray()) { + // As above, immediately scan arrays of binary data. + process_grey_object(obj); + } else { + if (_cm->verbose_high()) { + gclog_or_tty->print_cr( + "[%u] below the global finger (" PTR_FORMAT "), pushing " PTR_FORMAT, + _worker_id, p2i(global_finger), p2i(objAddr)); + } + push(obj); } - push(obj); } else { // do nothing } -#else // _CHECK_BOTH_FINGERS_ - // we will only check the global finger - - if (objAddr < global_finger) { - // see long comment above - - if (_cm->verbose_high()) { - gclog_or_tty->print_cr("[%u] below the global finger " - "("PTR_FORMAT"), pushing it", - _worker_id, p2i(global_finger)); - } - push(obj); - } -#endif // _CHECK_BOTH_FINGERS_ } } } diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp @@ -3472,30 +3472,50 @@ DirtyCardQueue _dcq; + // We don't nominate objects with many remembered set entries, on + // the assumption that such objects are likely still live. + bool is_remset_small(HeapRegion* region) const { + HeapRegionRemSet* const rset = region->rem_set(); + return G1EagerReclaimHumongousObjectsWithStaleRefs + ? rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries) + : rset->is_empty(); + } + + bool is_typeArray_region(HeapRegion* region) const { + return oop(region->bottom())->is_typeArray(); + } + bool humongous_region_is_candidate(G1CollectedHeap* heap, HeapRegion* region) const { assert(region->is_starts_humongous(), "Must start a humongous object"); - if (heap->mark_in_progress() && - (region->bottom() < region->next_top_at_mark_start())) { - // While concurrent marking is in progress, disallow eager - // reclaim of humongous objects that existed at the start of the - // marking cycle. For objects containing references, this - // avoids SATB violations; such objects must be scanned. This - // also avoids problems when eagerly reclaiming an object that - // has been marked and placed in the mark stack, but has not yet - // been scanned. - return false; - } else if (!oop(region->bottom())->is_typeArray()) { - // For now, only permit reclaiming of humongous is_typeArray() - // objects. For objects containing references, there is more - // work to be done to deal with remembered sets from the object. - return false; + + if (!heap->mark_in_progress() + || (region->bottom() >= region->next_top_at_mark_start())) { + // In order to maintain SATB invariants, during concurrent mark + // we should only nominate an object containing references if it + // was allocated after the start of marking, as such an object + // doesn't need to have its references scanned. + // + // Also, we must not reclaim an object that is in the concurrent + // mark stack. Objects allocated since the start of marking are + // never added to the mark stack. + + // However, we presently only nominate is_typeArray() objects. + // A humongous object containing references induces remembered + // set entries on other regions. In order to reclaim such an + // object, those remembered sets would need to be cleaned up. + return is_typeArray_region(region) && is_remset_small(region); + } else { - HeapRegionRemSet* const rset = region->rem_set(); - if (G1EagerReclaimHumongousObjectsWithStaleRefs) { - return rset->occupancy_less_or_equal_than(G1RSetSparseRegionEntries); - } else { - return rset->is_empty(); - } + // We may allow nomination of is_typeArray() objects that were + // allocated before the start of concurrent marking. For this + // we rely on mark stack insertion to exclude is_typeArray() + // objects, preventing reclaiming an object that is in the mark + // stack. Frequent allocation and drop of large binary blobs is + // an important use case for eager reclaim, and this special + // handling may reduce needed headroom. + return G1EagerReclaimHumongousPreSnapshotTypeArrays + && is_typeArray_region(region) + && is_remset_small(region); } } diff --git a/src/share/vm/gc_implementation/g1/g1_globals.hpp b/src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -277,6 +277,10 @@ "Try to reclaim dead large objects that have a few stale " \ "references at every young GC.") \ \ + experimental(bool, G1EagerReclaimHumongousPreSnapshotTypeArrays, true, \ + "Try to reclaim of dead large typeArray objects even when " \ + "allocated before an in-progress concurrent mark phase.") \ + \ experimental(bool, G1TraceEagerReclaimHumongousObjects, false, \ "Print some information about large object liveness " \ "at every young GC.") \