8151386: Extract card live data out of G1ConcurrentMark

Move card live data management out of G1ConcurrentMark into extra class G1CardLiveData managed by G1RemSet

Reviewed-by: mgerdin, kbarrett
This commit is contained in:
Thomas Schatzl 2016-04-06 13:41:59 +02:00
parent 0c06163b35
commit a009aa9ca7
17 changed files with 848 additions and 613 deletions

View file

@ -28,6 +28,7 @@
#include "gc/g1/g1Analytics.hpp" #include "gc/g1/g1Analytics.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1MMUTracker.hpp" #include "gc/g1/g1MMUTracker.hpp"
#include "gc/g1/suspendibleThreadSet.hpp" #include "gc/g1/suspendibleThreadSet.hpp"
#include "gc/g1/vm_operations_g1.hpp" #include "gc/g1/vm_operations_g1.hpp"

View file

@ -0,0 +1,552 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1CardLiveData.inline.hpp"
#include "gc/g1/suspendibleThreadSet.hpp"
#include "gc/shared/workgroup.hpp"
#include "memory/universe.hpp"
#include "runtime/atomic.inline.hpp"
#include "runtime/globals.hpp"
#include "runtime/os.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/debug.hpp"
G1CardLiveData::G1CardLiveData() :
_max_capacity(0),
_cards_per_region(0),
_live_regions(NULL),
_live_regions_size_in_bits(0),
_live_cards(NULL),
_live_cards_size_in_bits(0) {
}
G1CardLiveData::~G1CardLiveData() {
free_large_bitmap(_live_cards, _live_cards_size_in_bits);
free_large_bitmap(_live_regions, _live_regions_size_in_bits);
}
G1CardLiveData::bm_word_t* G1CardLiveData::allocate_large_bitmap(size_t size_in_bits) {
size_t size_in_words = BitMap::calc_size_in_words(size_in_bits);
bm_word_t* map = MmapArrayAllocator<bm_word_t, mtGC>::allocate(size_in_words);
return map;
}
void G1CardLiveData::free_large_bitmap(bm_word_t* bitmap, size_t size_in_bits) {
MmapArrayAllocator<bm_word_t, mtGC>::free(bitmap, size_in_bits / BitsPerWord);
}
void G1CardLiveData::initialize(size_t max_capacity, uint num_max_regions) {
assert(max_capacity % num_max_regions == 0,
"Given capacity must be evenly divisible by region size.");
size_t region_size = max_capacity / num_max_regions;
assert(region_size % (G1SATBCardTableModRefBS::card_size * BitsPerWord) == 0,
"Region size must be evenly divisible by area covered by a single word.");
_max_capacity = max_capacity;
_cards_per_region = region_size / G1SATBCardTableModRefBS::card_size;
_live_regions_size_in_bits = live_region_bitmap_size_in_bits();
_live_regions = allocate_large_bitmap(_live_regions_size_in_bits);
_live_cards_size_in_bits = live_card_bitmap_size_in_bits();
_live_cards = allocate_large_bitmap(_live_cards_size_in_bits);
}
void G1CardLiveData::pretouch() {
live_cards_bm().pretouch();
live_regions_bm().pretouch();
}
size_t G1CardLiveData::live_region_bitmap_size_in_bits() const {
return _max_capacity / (_cards_per_region << G1SATBCardTableModRefBS::card_shift);
}
size_t G1CardLiveData::live_card_bitmap_size_in_bits() const {
return _max_capacity >> G1SATBCardTableModRefBS::card_shift;
}
// Helper class that provides functionality to generate the Live Data Count
// information.
class G1CardLiveDataHelper VALUE_OBJ_CLASS_SPEC {
private:
BitMap _region_bm;
BitMap _card_bm;
// The card number of the bottom of the G1 heap.
// Used in biasing indices into accounting card bitmaps.
BitMap::idx_t _heap_card_bias;
// Utility routine to set an exclusive range of bits on the given
// bitmap, optimized for very small ranges.
// There must be at least one bit to set.
void set_card_bitmap_range(BitMap::idx_t start_idx,
BitMap::idx_t end_idx) {
// Set the exclusive bit range [start_idx, end_idx).
assert((end_idx - start_idx) > 0, "at least one bit");
// For small ranges use a simple loop; otherwise use set_range.
// The range is made up of the cards that are spanned by an object/mem
// region so 8 cards will allow up to object sizes up to 4K to be handled
// using the loop.
if ((end_idx - start_idx) <= 8) {
for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) {
_card_bm.set_bit(i);
}
} else {
_card_bm.set_range(start_idx, end_idx);
}
}
// We cache the last mark set. This avoids setting the same bit multiple times.
// This is particularly interesting for dense bitmaps, as this avoids doing
// lots of work most of the time.
BitMap::idx_t _last_marked_bit_idx;
// Mark the card liveness bitmap for the object spanning from start to end.
void mark_card_bitmap_range(HeapWord* start, HeapWord* end) {
BitMap::idx_t start_idx = card_live_bitmap_index_for(start);
BitMap::idx_t end_idx = card_live_bitmap_index_for((HeapWord*)align_ptr_up(end, CardTableModRefBS::card_size));
assert((end_idx - start_idx) > 0, "Trying to mark zero sized range.");
if (start_idx == _last_marked_bit_idx) {
start_idx++;
}
if (start_idx == end_idx) {
return;
}
// Set the bits in the card bitmap for the cards spanned by this object.
set_card_bitmap_range(start_idx, end_idx);
_last_marked_bit_idx = end_idx - 1;
}
void reset_mark_cache() {
_last_marked_bit_idx = (BitMap::idx_t)-1;
}
public:
// Returns the index in the per-card liveness count bitmap
// for the given address
inline BitMap::idx_t card_live_bitmap_index_for(HeapWord* addr) {
// Below, the term "card num" means the result of shifting an address
// by the card shift -- address 0 corresponds to card number 0. One
// must subtract the card num of the bottom of the heap to obtain a
// card table index.
BitMap::idx_t card_num = uintptr_t(addr) >> CardTableModRefBS::card_shift;
return card_num - _heap_card_bias;
}
// Takes a region that's not empty (i.e., it has at least one
// live object in it and sets its corresponding bit on the region
// bitmap to 1.
void set_bit_for_region(HeapRegion* hr) {
_region_bm.par_set_bit(hr->hrm_index());
}
// Mark the range of bits covered by allocations done since the last marking
// in the given heap region, i.e. from NTAMS to top of the given region.
// Returns if there has been some allocation in this region since the last marking.
bool mark_allocated_since_marking(HeapRegion* hr) {
reset_mark_cache();
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* top = hr->top();
assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions.");
// Mark the allocated-since-marking portion...
if (ntams < top) {
mark_card_bitmap_range(ntams, top);
return true;
} else {
return false;
}
}
// Mark the range of bits covered by live objects on the mark bitmap between
// bottom and NTAMS of the given region.
// Returns the number of live bytes marked within that area for the given
// heap region.
size_t mark_marked_during_marking(G1CMBitMap* mark_bitmap, HeapRegion* hr) {
reset_mark_cache();
size_t marked_bytes = 0;
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* start = hr->bottom();
if (ntams <= start) {
// Skip empty regions.
return 0;
}
if (hr->is_humongous()) {
mark_card_bitmap_range(start, hr->top());
return pointer_delta(hr->top(), start, 1);
}
assert(start <= hr->end() && start <= ntams && ntams <= hr->end(),
"Preconditions not met - "
"start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT,
p2i(start), p2i(ntams), p2i(hr->end()));
// Find the first marked object at or after "start".
start = mark_bitmap->getNextMarkedWordAddress(start, ntams);
while (start < ntams) {
oop obj = oop(start);
size_t obj_size = obj->size();
HeapWord* obj_end = start + obj_size;
assert(obj_end <= hr->end(), "Humongous objects must have been handled elsewhere.");
mark_card_bitmap_range(start, obj_end);
// Add the size of this object to the number of marked bytes.
marked_bytes += obj_size * HeapWordSize;
// Find the next marked object after this one.
start = mark_bitmap->getNextMarkedWordAddress(obj_end, ntams);
}
return marked_bytes;
}
G1CardLiveDataHelper(G1CardLiveData* live_data, HeapWord* base_address) :
_region_bm(live_data->live_regions_bm()),
_card_bm(live_data->live_cards_bm()) {
// Calculate the card number for the bottom of the heap. Used
// in biasing indexes into the accounting card bitmaps.
_heap_card_bias =
uintptr_t(base_address) >> CardTableModRefBS::card_shift;
}
};
class G1CreateCardLiveDataTask: public AbstractGangTask {
// Aggregate the counting data that was constructed concurrently
// with marking.
class G1CreateLiveDataClosure : public HeapRegionClosure {
G1CardLiveDataHelper _helper;
G1CMBitMap* _mark_bitmap;
G1ConcurrentMark* _cm;
public:
G1CreateLiveDataClosure(G1CollectedHeap* g1h,
G1ConcurrentMark* cm,
G1CMBitMap* mark_bitmap,
G1CardLiveData* live_data) :
HeapRegionClosure(),
_helper(live_data, g1h->reserved_region().start()),
_mark_bitmap(mark_bitmap),
_cm(cm) { }
bool doHeapRegion(HeapRegion* hr) {
size_t marked_bytes = _helper.mark_marked_during_marking(_mark_bitmap, hr);
if (marked_bytes > 0) {
hr->add_to_marked_bytes(marked_bytes);
}
return (_cm->do_yield_check() && _cm->has_aborted());
}
};
G1ConcurrentMark* _cm;
G1CardLiveData* _live_data;
HeapRegionClaimer _hr_claimer;
public:
G1CreateCardLiveDataTask(G1CMBitMap* bitmap,
G1CardLiveData* live_data,
uint n_workers) :
AbstractGangTask("G1 Create Live Data"),
_live_data(live_data),
_hr_claimer(n_workers) {
}
void work(uint worker_id) {
SuspendibleThreadSetJoiner sts_join;
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1ConcurrentMark* cm = g1h->concurrent_mark();
G1CreateLiveDataClosure cl(g1h, cm, cm->nextMarkBitMap(), _live_data);
g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
}
};
void G1CardLiveData::create(WorkGang* workers, G1CMBitMap* mark_bitmap) {
uint n_workers = workers->active_workers();
G1CreateCardLiveDataTask cl(mark_bitmap,
this,
n_workers);
workers->run_task(&cl);
}
class G1FinalizeCardLiveDataTask: public AbstractGangTask {
// Finalizes the liveness counting data.
// Sets the bits corresponding to the interval [NTAMS, top]
// (which contains the implicitly live objects) in the
// card liveness bitmap. Also sets the bit for each region
// containing live data, in the region liveness bitmap.
class G1FinalizeCardLiveDataClosure: public HeapRegionClosure {
private:
G1CardLiveDataHelper _helper;
public:
G1FinalizeCardLiveDataClosure(G1CollectedHeap* g1h,
G1CMBitMap* bitmap,
G1CardLiveData* live_data) :
HeapRegionClosure(),
_helper(live_data, g1h->reserved_region().start()) { }
bool doHeapRegion(HeapRegion* hr) {
bool allocated_since_marking = _helper.mark_allocated_since_marking(hr);
if (allocated_since_marking || hr->next_marked_bytes() > 0) {
_helper.set_bit_for_region(hr);
}
return false;
}
};
G1CMBitMap* _bitmap;
G1CardLiveData* _live_data;
HeapRegionClaimer _hr_claimer;
public:
G1FinalizeCardLiveDataTask(G1CMBitMap* bitmap, G1CardLiveData* live_data, uint n_workers) :
AbstractGangTask("G1 Finalize Card Live Data"),
_bitmap(bitmap),
_live_data(live_data),
_hr_claimer(n_workers) {
}
void work(uint worker_id) {
G1FinalizeCardLiveDataClosure cl(G1CollectedHeap::heap(), _bitmap, _live_data);
G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
}
};
void G1CardLiveData::finalize(WorkGang* workers, G1CMBitMap* mark_bitmap) {
// Finalize the live data.
G1FinalizeCardLiveDataTask cl(mark_bitmap,
this,
workers->active_workers());
workers->run_task(&cl);
}
class G1ClearCardLiveDataTask : public AbstractGangTask {
BitMap _bitmap;
size_t _num_chunks;
size_t _cur_chunk;
public:
G1ClearCardLiveDataTask(BitMap bitmap, size_t num_tasks) :
AbstractGangTask("G1 Clear Card Live Data"),
_bitmap(bitmap),
_num_chunks(num_tasks),
_cur_chunk(0) {
}
static size_t chunk_size() { return M; }
virtual void work(uint worker_id) {
while (true) {
size_t to_process = Atomic::add(1, &_cur_chunk) - 1;
if (to_process >= _num_chunks) {
break;
}
BitMap::idx_t start = M * BitsPerByte * to_process;
BitMap::idx_t end = MIN2(start + M * BitsPerByte, _bitmap.size());
_bitmap.clear_range(start, end);
}
}
};
void G1CardLiveData::clear(WorkGang* workers) {
guarantee(Universe::is_fully_initialized(), "Should not call this during initialization.");
size_t const num_chunks = align_size_up(live_cards_bm().size_in_bytes(), G1ClearCardLiveDataTask::chunk_size()) / G1ClearCardLiveDataTask::chunk_size();
G1ClearCardLiveDataTask cl(live_cards_bm(), num_chunks);
workers->run_task(&cl);
// The region live bitmap is always very small, even for huge heaps. Clear
// directly.
live_regions_bm().clear();
}
class G1VerifyCardLiveDataTask: public AbstractGangTask {
// Heap region closure used for verifying the live count data
// that was created concurrently and finalized during
// the remark pause. This closure is applied to the heap
// regions during the STW cleanup pause.
class G1VerifyCardLiveDataClosure: public HeapRegionClosure {
private:
G1CollectedHeap* _g1h;
G1CMBitMap* _mark_bitmap;
G1CardLiveDataHelper _helper;
G1CardLiveData* _act_live_data;
G1CardLiveData* _exp_live_data;
int _failures;
// Completely recreates the live data count for the given heap region and
// returns the number of bytes marked.
size_t create_live_data_count(HeapRegion* hr) {
size_t bytes_marked = _helper.mark_marked_during_marking(_mark_bitmap, hr);
bool allocated_since_marking = _helper.mark_allocated_since_marking(hr);
if (allocated_since_marking || bytes_marked > 0) {
_helper.set_bit_for_region(hr);
}
return bytes_marked;
}
public:
G1VerifyCardLiveDataClosure(G1CollectedHeap* g1h,
G1CMBitMap* mark_bitmap,
G1CardLiveData* act_live_data,
G1CardLiveData* exp_live_data) :
_g1h(g1h),
_mark_bitmap(mark_bitmap),
_helper(exp_live_data, g1h->reserved_region().start()),
_act_live_data(act_live_data),
_exp_live_data(exp_live_data),
_failures(0) { }
int failures() const { return _failures; }
bool doHeapRegion(HeapRegion* hr) {
int failures = 0;
// Walk the marking bitmap for this region and set the corresponding bits
// in the expected region and card bitmaps.
size_t exp_marked_bytes = create_live_data_count(hr);
size_t act_marked_bytes = hr->next_marked_bytes();
// Verify the marked bytes for this region.
if (exp_marked_bytes != act_marked_bytes) {
failures += 1;
} else if (exp_marked_bytes > HeapRegion::GrainBytes) {
failures += 1;
}
// Verify the bit, for this region, in the actual and expected
// (which was just calculated) region bit maps.
// We're not OK if the bit in the calculated expected region
// bitmap is set and the bit in the actual region bitmap is not.
uint index = hr->hrm_index();
bool expected = _exp_live_data->is_region_live(index);
bool actual = _act_live_data->is_region_live(index);
if (expected && !actual) {
failures += 1;
}
// Verify that the card bit maps for the cards spanned by the current
// region match. We have an error if we have a set bit in the expected
// bit map and the corresponding bit in the actual bitmap is not set.
BitMap::idx_t start_idx = _helper.card_live_bitmap_index_for(hr->bottom());
BitMap::idx_t end_idx = _helper.card_live_bitmap_index_for(hr->top());
for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) {
expected = _exp_live_data->is_card_live_at(i);
actual = _act_live_data->is_card_live_at(i);
if (expected && !actual) {
failures += 1;
}
}
_failures += failures;
// We could stop iteration over the heap when we
// find the first violating region by returning true.
return false;
}
};
protected:
G1CollectedHeap* _g1h;
G1CMBitMap* _mark_bitmap;
G1CardLiveData* _act_live_data;
G1CardLiveData _exp_live_data;
int _failures;
HeapRegionClaimer _hr_claimer;
public:
G1VerifyCardLiveDataTask(G1CMBitMap* bitmap,
G1CardLiveData* act_live_data,
uint n_workers)
: AbstractGangTask("G1 Verify Card Live Data"),
_g1h(G1CollectedHeap::heap()),
_mark_bitmap(bitmap),
_act_live_data(act_live_data),
_exp_live_data(),
_failures(0),
_hr_claimer(n_workers) {
assert(VerifyDuringGC, "don't call this otherwise");
_exp_live_data.initialize(_g1h->max_capacity(), _g1h->max_regions());
}
void work(uint worker_id) {
G1VerifyCardLiveDataClosure cl(_g1h,
_mark_bitmap,
_act_live_data,
&_exp_live_data);
_g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
Atomic::add(cl.failures(), &_failures);
}
int failures() const { return _failures; }
};
void G1CardLiveData::verify(WorkGang* workers, G1CMBitMap* actual_bitmap) {
ResourceMark rm;
G1VerifyCardLiveDataTask cl(actual_bitmap,
this,
workers->active_workers());
workers->run_task(&cl);
guarantee(cl.failures() == 0, "Unexpected accounting failures");
}
#ifndef PRODUCT
void G1CardLiveData::verify_is_clear() {
assert(live_cards_bm().count_one_bits() == 0, "Live cards bitmap must be clear.");
assert(live_regions_bm().count_one_bits() == 0, "Live regions bitmap must be clear.");
}
#endif

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP
#define SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP
#include "gc/g1/g1CollectedHeap.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/globalDefinitions.hpp"
class G1CollectedHeap;
class G1CMBitMap;
class WorkGang;
// Information about object liveness on the Java heap on a "card" basis.
// Can be used for various purposes, like as remembered set for completely
// coarsened remembered sets, scrubbing remembered sets or estimating liveness.
// This information is created as part of the concurrent marking cycle.
class G1CardLiveData VALUE_OBJ_CLASS_SPEC {
friend class G1CardLiveDataHelper;
friend class G1VerifyCardLiveDataTask;
private:
typedef BitMap::bm_word_t bm_word_t;
// Store some additional information about the covered area to be able to test.
size_t _max_capacity;
size_t _cards_per_region;
// The per-card liveness bitmap.
bm_word_t* _live_cards;
size_t _live_cards_size_in_bits;
// The per-region liveness bitmap.
bm_word_t* _live_regions;
size_t _live_regions_size_in_bits;
// The bits in this bitmap contain for every card whether it contains
// at least part of at least one live object.
BitMap live_cards_bm() const { return BitMap(_live_cards, _live_cards_size_in_bits); }
// The bits in this bitmap indicate that a given region contains some live objects.
BitMap live_regions_bm() const { return BitMap(_live_regions, _live_regions_size_in_bits); }
// Allocate a "large" bitmap from virtual memory with the given size in bits.
bm_word_t* allocate_large_bitmap(size_t size_in_bits);
void free_large_bitmap(bm_word_t* map, size_t size_in_bits);
inline BitMap live_card_bitmap(uint region);
inline bool is_card_live_at(BitMap::idx_t idx) const;
size_t live_region_bitmap_size_in_bits() const;
size_t live_card_bitmap_size_in_bits() const;
public:
inline bool is_region_live(uint region) const;
inline void remove_nonlive_cards(uint region, BitMap* bm);
inline void remove_nonlive_regions(BitMap* bm);
G1CardLiveData();
~G1CardLiveData();
void initialize(size_t max_capacity, uint num_max_regions);
void pretouch();
// Create the initial liveness data based on the marking result from the bottom
// to the ntams of every region in the heap and the marks in the given bitmap.
void create(WorkGang* workers, G1CMBitMap* mark_bitmap);
// Finalize the liveness data.
void finalize(WorkGang* workers, G1CMBitMap* mark_bitmap);
// Verify that the liveness count data created concurrently matches one created
// during this safepoint.
void verify(WorkGang* workers, G1CMBitMap* actual_bitmap);
// Clear all data structures, prepare for next processing.
void clear(WorkGang* workers);
void verify_is_clear() PRODUCT_RETURN;
};
#endif /* SHARE_VM_GC_G1_G1CARDLIVEDATA_HPP */

View file

@ -0,0 +1,52 @@
/*
* Copyright (c) 2016, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP
#define SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP
#include "gc/g1/g1CardLiveData.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/globalDefinitions.hpp"
inline BitMap G1CardLiveData::live_card_bitmap(uint region) {
return BitMap(_live_cards + ((size_t)region * _cards_per_region >> LogBitsPerWord), _cards_per_region);
}
inline bool G1CardLiveData::is_card_live_at(BitMap::idx_t idx) const {
return live_cards_bm().at(idx);
}
inline bool G1CardLiveData::is_region_live(uint region) const {
return live_regions_bm().at(region);
}
inline void G1CardLiveData::remove_nonlive_cards(uint region, BitMap* bm) {
bm->set_intersection(live_card_bitmap(region));
}
inline void G1CardLiveData::remove_nonlive_regions(BitMap* bm) {
bm->set_intersection(live_regions_bm());
}
#endif /* SHARE_VM_GC_G1_G1CARDLIVEDATA_INLINE_HPP */

View file

@ -1425,6 +1425,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
// the full GC has compacted objects and updated TAMS but not updated // the full GC has compacted objects and updated TAMS but not updated
// the prev bitmap. // the prev bitmap.
if (G1VerifyBitmaps) { if (G1VerifyBitmaps) {
GCTraceTime(Debug, gc)("Clear Bitmap for Verification");
_cm->clear_prev_bitmap(workers()); _cm->clear_prev_bitmap(workers());
} }
_verifier->check_bitmaps("Full GC End"); _verifier->check_bitmaps("Full GC End");
@ -1944,7 +1945,7 @@ jint G1CollectedHeap::initialize() {
const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1; const uint max_region_idx = (1U << (sizeof(RegionIdx_t)*BitsPerByte-1)) - 1;
guarantee((max_regions() - 1) <= max_region_idx, "too many regions"); guarantee((max_regions() - 1) <= max_region_idx, "too many regions");
G1RemSet::initialize(max_regions()); g1_rem_set()->initialize(max_capacity(), max_regions());
size_t max_cards_per_region = ((size_t)1 << (sizeof(CardIdx_t)*BitsPerByte-1)) - 1; size_t max_cards_per_region = ((size_t)1 << (sizeof(CardIdx_t)*BitsPerByte-1)) - 1;
guarantee(HeapRegion::CardsPerRegion > 0, "make sure it's initialized"); guarantee(HeapRegion::CardsPerRegion > 0, "make sure it's initialized");
@ -4787,27 +4788,23 @@ public:
class G1ParScrubRemSetTask: public AbstractGangTask { class G1ParScrubRemSetTask: public AbstractGangTask {
protected: protected:
G1RemSet* _g1rs; G1RemSet* _g1rs;
BitMap* _region_bm;
BitMap* _card_bm;
HeapRegionClaimer _hrclaimer; HeapRegionClaimer _hrclaimer;
public: public:
G1ParScrubRemSetTask(G1RemSet* g1_rs, BitMap* region_bm, BitMap* card_bm, uint num_workers) : G1ParScrubRemSetTask(G1RemSet* g1_rs, uint num_workers) :
AbstractGangTask("G1 ScrubRS"), AbstractGangTask("G1 ScrubRS"),
_g1rs(g1_rs), _g1rs(g1_rs),
_region_bm(region_bm),
_card_bm(card_bm),
_hrclaimer(num_workers) { _hrclaimer(num_workers) {
} }
void work(uint worker_id) { void work(uint worker_id) {
_g1rs->scrub(_region_bm, _card_bm, worker_id, &_hrclaimer); _g1rs->scrub(worker_id, &_hrclaimer);
} }
}; };
void G1CollectedHeap::scrub_rem_set(BitMap* region_bm, BitMap* card_bm) { void G1CollectedHeap::scrub_rem_set() {
uint num_workers = workers()->active_workers(); uint num_workers = workers()->active_workers();
G1ParScrubRemSetTask g1_par_scrub_rs_task(g1_rem_set(), region_bm, card_bm, num_workers); G1ParScrubRemSetTask g1_par_scrub_rs_task(g1_rem_set(), num_workers);
workers()->run_task(&g1_par_scrub_rs_task); workers()->run_task(&g1_par_scrub_rs_task);
} }

View file

@ -992,7 +992,8 @@ public:
// The rem set and barrier set. // The rem set and barrier set.
G1RemSet* g1_rem_set() const { return _g1_rem_set; } G1RemSet* g1_rem_set() const { return _g1_rem_set; }
void scrub_rem_set(BitMap* region_bm, BitMap* card_bm); // Try to minimize the remembered set.
void scrub_rem_set();
unsigned get_gc_time_stamp() { unsigned get_gc_time_stamp() {
return _gc_time_stamp; return _gc_time_stamp;

View file

@ -28,7 +28,7 @@
#include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1CollectorPolicy.hpp" #include "gc/g1/g1CollectorPolicy.hpp"
#include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1SATBCardTableModRefBS.hpp" #include "gc/g1/g1SATBCardTableModRefBS.hpp"
#include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp" #include "gc/g1/heapRegionSet.inline.hpp"

View file

@ -33,6 +33,7 @@
#include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp"
#include "gc/g1/g1HeapVerifier.hpp" #include "gc/g1/g1HeapVerifier.hpp"
#include "gc/g1/g1OopClosures.inline.hpp" #include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1CardLiveData.inline.hpp"
#include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1StringDedup.hpp"
#include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionRemSet.hpp"
@ -48,7 +49,6 @@
#include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/taskqueue.inline.hpp"
#include "gc/shared/vmGCOperations.hpp" #include "gc/shared/vmGCOperations.hpp"
#include "logging/log.hpp" #include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
@ -356,8 +356,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
_sleep_factor(0.0), _sleep_factor(0.0),
_marking_task_overhead(1.0), _marking_task_overhead(1.0),
_cleanup_list("Cleanup List"), _cleanup_list("Cleanup List"),
_region_live_bm(),
_card_live_bm(),
_prevMarkBitMap(&_markBitMap1), _prevMarkBitMap(&_markBitMap1),
_nextMarkBitMap(&_markBitMap2), _nextMarkBitMap(&_markBitMap2),
@ -499,12 +497,6 @@ G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper*
return; return;
} }
allocate_internal_bitmaps();
if (G1PretouchAuxiliaryMemory) {
pretouch_internal_bitmaps();
}
_tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC); _tasks = NEW_C_HEAP_ARRAY(G1CMTask*, _max_worker_id, mtGC);
_accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC); _accum_task_vtime = NEW_C_HEAP_ARRAY(double, _max_worker_id, mtGC);
@ -701,8 +693,8 @@ void G1ConcurrentMark::cleanup_for_next_mark() {
// Clear the live count data. If the marking has been aborted, the abort() // Clear the live count data. If the marking has been aborted, the abort()
// call already did that. // call already did that.
if (!has_aborted()) { if (!has_aborted()) {
clear_all_live_data(_parallel_workers); clear_live_data(_parallel_workers);
DEBUG_ONLY(verify_all_live_data()); DEBUG_ONLY(verify_live_data_clear());
} }
// Repeat the asserts from above. // Repeat the asserts from above.
@ -884,7 +876,7 @@ public:
double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec; double elapsed_vtime_sec = end_vtime_sec - start_vtime_sec;
_cm->clear_has_overflown(); _cm->clear_has_overflown();
_cm->do_yield_check(worker_id); _cm->do_yield_check();
jlong sleep_time_ms; jlong sleep_time_ms;
if (!_cm->has_aborted() && the_task->has_aborted()) { if (!_cm->has_aborted() && the_task->has_aborted()) {
@ -934,10 +926,10 @@ uint G1ConcurrentMark::calc_parallel_marking_threads() {
return n_conc_workers; return n_conc_workers;
} }
void G1ConcurrentMark::scanRootRegion(HeapRegion* hr, uint worker_id) { void G1ConcurrentMark::scanRootRegion(HeapRegion* hr) {
// Currently, only survivors can be root regions. // Currently, only survivors can be root regions.
assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant"); assert(hr->next_top_at_mark_start() == hr->bottom(), "invariant");
G1RootRegionScanClosure cl(_g1h, this, worker_id); G1RootRegionScanClosure cl(_g1h, this);
const uintx interval = PrefetchScanIntervalInBytes; const uintx interval = PrefetchScanIntervalInBytes;
HeapWord* curr = hr->bottom(); HeapWord* curr = hr->bottom();
@ -966,7 +958,7 @@ public:
G1CMRootRegions* root_regions = _cm->root_regions(); G1CMRootRegions* root_regions = _cm->root_regions();
HeapRegion* hr = root_regions->claim_next(); HeapRegion* hr = root_regions->claim_next();
while (hr != NULL) { while (hr != NULL) {
_cm->scanRootRegion(hr, worker_id); _cm->scanRootRegion(hr);
hr = root_regions->claim_next(); hr = root_regions->claim_next();
} }
} }
@ -1125,363 +1117,6 @@ void G1ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) {
_gc_tracer_cm->report_object_count_after_gc(&is_alive); _gc_tracer_cm->report_object_count_after_gc(&is_alive);
} }
// Helper class that provides functionality to generate the Live Data Count
// information.
class G1LiveDataHelper VALUE_OBJ_CLASS_SPEC {
private:
BitMap* _region_bm;
BitMap* _card_bm;
// The card number of the bottom of the G1 heap. Used for converting addresses
// to bitmap indices quickly.
BitMap::idx_t _heap_card_bias;
// Utility routine to set an exclusive range of bits on the given
// bitmap, optimized for very small ranges.
// There must be at least one bit to set.
inline void set_card_bitmap_range(BitMap* bm,
BitMap::idx_t start_idx,
BitMap::idx_t end_idx) {
// Set the exclusive bit range [start_idx, end_idx).
assert((end_idx - start_idx) > 0, "at least one bit");
assert(end_idx <= bm->size(), "sanity");
// For small ranges use a simple loop; otherwise use set_range or
// use par_at_put_range (if parallel). The range is made up of the
// cards that are spanned by an object/mem region so 8 cards will
// allow up to object sizes up to 4K to be handled using the loop.
if ((end_idx - start_idx) <= 8) {
for (BitMap::idx_t i = start_idx; i < end_idx; i += 1) {
bm->set_bit(i);
}
} else {
bm->set_range(start_idx, end_idx);
}
}
// We cache the last mark set. This avoids setting the same bit multiple times.
// This is particularly interesting for dense bitmaps, as this avoids doing
// lots of work most of the time.
BitMap::idx_t _last_marked_bit_idx;
// Mark the card liveness bitmap for the object spanning from start to end.
void mark_card_bitmap_range(HeapWord* start, HeapWord* end) {
BitMap::idx_t start_idx = card_live_bitmap_index_for(start);
BitMap::idx_t end_idx = card_live_bitmap_index_for((HeapWord*)align_ptr_up(end, CardTableModRefBS::card_size));
assert((end_idx - start_idx) > 0, "Trying to mark zero sized range.");
if (start_idx == _last_marked_bit_idx) {
start_idx++;
}
if (start_idx == end_idx) {
return;
}
// Set the bits in the card bitmap for the cards spanned by this object.
set_card_bitmap_range(_card_bm, start_idx, end_idx);
_last_marked_bit_idx = end_idx - 1;
}
void reset_mark_cache() {
_last_marked_bit_idx = (BitMap::idx_t)-1;
}
public:
// Returns the index in the per-card liveness count bitmap
// for the given address
inline BitMap::idx_t card_live_bitmap_index_for(HeapWord* addr) {
// Below, the term "card num" means the result of shifting an address
// by the card shift -- address 0 corresponds to card number 0. One
// must subtract the card num of the bottom of the heap to obtain a
// card table index.
BitMap::idx_t card_num = (BitMap::idx_t)(uintptr_t(addr) >> CardTableModRefBS::card_shift);
return card_num - _heap_card_bias;
}
// Takes a region that's not empty (i.e., it has at least one
// live object in it and sets its corresponding bit on the region
// bitmap to 1.
void set_bit_for_region(HeapRegion* hr) {
BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
_region_bm->par_at_put(index, true);
}
// Mark the range of bits covered by allocations done since the last marking
// in the given heap region, i.e. from NTAMS to top of the given region.
// Returns if there has been some allocation in this region since the last marking.
bool mark_allocated_since_marking(HeapRegion* hr) {
reset_mark_cache();
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* top = hr->top();
assert(hr->bottom() <= ntams && ntams <= hr->end(), "Preconditions.");
// Mark the allocated-since-marking portion...
if (ntams < top) {
mark_card_bitmap_range(ntams, top);
return true;
} else {
return false;
}
}
// Mark the range of bits covered by live objects on the mark bitmap between
// bottom and NTAMS of the given region.
// Returns the number of live bytes marked within that area for the given
// heap region.
size_t mark_marked_during_marking(G1CMBitMap* mark_bitmap, HeapRegion* hr) {
reset_mark_cache();
size_t marked_bytes = 0;
HeapWord* ntams = hr->next_top_at_mark_start();
HeapWord* start = hr->bottom();
if (ntams <= start) {
// Skip empty regions.
return 0;
} else if (hr->is_humongous()) {
mark_card_bitmap_range(start, hr->top());
return pointer_delta(hr->top(), start, 1);
}
assert(start <= hr->end() && start <= ntams && ntams <= hr->end(),
"Preconditions not met - "
"start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT,
p2i(start), p2i(ntams), p2i(hr->end()));
// Find the first marked object at or after "start".
start = mark_bitmap->getNextMarkedWordAddress(start, ntams);
while (start < ntams) {
oop obj = oop(start);
int obj_sz = obj->size();
HeapWord* obj_end = start + obj_sz;
assert(obj_end <= hr->end(), "Humongous objects must have been handled elsewhere.");
mark_card_bitmap_range(start, obj_end);
// Add the size of this object to the number of marked bytes.
marked_bytes += (size_t)obj_sz * HeapWordSize;
// Find the next marked object after this one.
start = mark_bitmap->getNextMarkedWordAddress(obj_end, ntams);
}
return marked_bytes;
}
G1LiveDataHelper(BitMap* region_bm,
BitMap* card_bm):
_region_bm(region_bm),
_card_bm(card_bm) {
//assert(region_bm != NULL, "");
assert(card_bm != NULL, "");
// Calculate the card number for the bottom of the heap. Used
// in biasing indexes into the accounting card bitmaps.
_heap_card_bias =
(BitMap::idx_t)(uintptr_t(G1CollectedHeap::heap()->reserved_region().start()) >> CardTableModRefBS::card_shift);
}
};
// Heap region closure used for verifying the live count data
// that was created concurrently and finalized during
// the remark pause. This closure is applied to the heap
// regions during the STW cleanup pause.
class G1VerifyLiveDataHRClosure: public HeapRegionClosure {
private:
G1CollectedHeap* _g1h;
G1CMBitMap* _mark_bitmap;
G1LiveDataHelper _calc_helper;
BitMap* _act_region_bm; // Region BM to be verified
BitMap* _act_card_bm; // Card BM to be verified
BitMap* _exp_region_bm; // Expected Region BM values
BitMap* _exp_card_bm; // Expected card BM values
int _failures;
// Updates the live data count for the given heap region and returns the number
// of bytes marked.
size_t create_live_data_count(HeapRegion* hr) {
size_t bytes_marked = _calc_helper.mark_marked_during_marking(_mark_bitmap, hr);
bool allocated_since_marking = _calc_helper.mark_allocated_since_marking(hr);
if (allocated_since_marking || bytes_marked > 0) {
_calc_helper.set_bit_for_region(hr);
}
return bytes_marked;
}
public:
G1VerifyLiveDataHRClosure(G1CollectedHeap* g1h,
G1CMBitMap* mark_bitmap,
BitMap* act_region_bm,
BitMap* act_card_bm,
BitMap* exp_region_bm,
BitMap* exp_card_bm) :
_g1h(g1h),
_mark_bitmap(mark_bitmap),
_calc_helper(exp_region_bm, exp_card_bm),
_act_region_bm(act_region_bm),
_act_card_bm(act_card_bm),
_exp_region_bm(exp_region_bm),
_exp_card_bm(exp_card_bm),
_failures(0) { }
int failures() const { return _failures; }
bool doHeapRegion(HeapRegion* hr) {
int failures = 0;
// Walk the marking bitmap for this region and set the corresponding bits
// in the expected region and card bitmaps.
size_t exp_marked_bytes = create_live_data_count(hr);
size_t act_marked_bytes = hr->next_marked_bytes();
// Verify the marked bytes for this region.
if (exp_marked_bytes != act_marked_bytes) {
failures += 1;
} else if (exp_marked_bytes > HeapRegion::GrainBytes) {
failures += 1;
}
// Verify the bit, for this region, in the actual and expected
// (which was just calculated) region bit maps.
// We're not OK if the bit in the calculated expected region
// bitmap is set and the bit in the actual region bitmap is not.
BitMap::idx_t index = (BitMap::idx_t) hr->hrm_index();
bool expected = _exp_region_bm->at(index);
bool actual = _act_region_bm->at(index);
if (expected && !actual) {
failures += 1;
}
// Verify that the card bit maps for the cards spanned by the current
// region match. We have an error if we have a set bit in the expected
// bit map and the corresponding bit in the actual bitmap is not set.
BitMap::idx_t start_idx = _calc_helper.card_live_bitmap_index_for(hr->bottom());
BitMap::idx_t end_idx = _calc_helper.card_live_bitmap_index_for(hr->top());
for (BitMap::idx_t i = start_idx; i < end_idx; i+=1) {
expected = _exp_card_bm->at(i);
actual = _act_card_bm->at(i);
if (expected && !actual) {
failures += 1;
}
}
_failures += failures;
// We could stop iteration over the heap when we
// find the first violating region by returning true.
return false;
}
};
class G1VerifyLiveDataTask: public AbstractGangTask {
protected:
G1CollectedHeap* _g1h;
G1CMBitMap* _mark_bitmap;
BitMap* _actual_region_bm;
BitMap* _actual_card_bm;
BitMap _expected_region_bm;
BitMap _expected_card_bm;
int _failures;
HeapRegionClaimer _hr_claimer;
public:
G1VerifyLiveDataTask(G1CollectedHeap* g1h,
G1CMBitMap* bitmap,
BitMap* region_bm,
BitMap* card_bm,
uint n_workers)
: AbstractGangTask("G1 verify final counting"),
_g1h(g1h),
_mark_bitmap(bitmap),
_actual_region_bm(region_bm),
_actual_card_bm(card_bm),
_expected_region_bm(region_bm->size(), true /* in_resource_area */),
_expected_card_bm(card_bm->size(), true /* in_resource_area */),
_failures(0),
_hr_claimer(n_workers) {
assert(VerifyDuringGC, "don't call this otherwise");
}
void work(uint worker_id) {
G1VerifyLiveDataHRClosure cl(_g1h,
_mark_bitmap,
_actual_region_bm,
_actual_card_bm,
&_expected_region_bm,
&_expected_card_bm);
_g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
Atomic::add(cl.failures(), &_failures);
}
int failures() const { return _failures; }
};
class G1FinalizeLiveDataTask: public AbstractGangTask {
// Finalizes the liveness counting data.
// Sets the bits corresponding to the interval [NTAMS, top]
// (which contains the implicitly live objects) in the
// card liveness bitmap. Also sets the bit for each region
// containing live data, in the region liveness bitmap.
class G1FinalizeCountDataClosure: public HeapRegionClosure {
private:
G1LiveDataHelper _helper;
public:
G1FinalizeCountDataClosure(G1CMBitMap* bitmap,
BitMap* region_bm,
BitMap* card_bm) :
HeapRegionClosure(),
_helper(region_bm, card_bm) { }
bool doHeapRegion(HeapRegion* hr) {
bool allocated_since_marking = _helper.mark_allocated_since_marking(hr);
if (allocated_since_marking || hr->next_marked_bytes() > 0) {
_helper.set_bit_for_region(hr);
}
return false;
}
};
G1CMBitMap* _bitmap;
BitMap* _actual_region_bm;
BitMap* _actual_card_bm;
HeapRegionClaimer _hr_claimer;
public:
G1FinalizeLiveDataTask(G1CMBitMap* bitmap, BitMap* region_bm, BitMap* card_bm, uint n_workers) :
AbstractGangTask("G1 final counting"),
_bitmap(bitmap),
_actual_region_bm(region_bm),
_actual_card_bm(card_bm),
_hr_claimer(n_workers) {
}
void work(uint worker_id) {
G1FinalizeCountDataClosure cl(_bitmap,
_actual_region_bm,
_actual_card_bm);
G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
}
};
class G1NoteEndOfConcMarkClosure : public HeapRegionClosure { class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
G1CollectedHeap* _g1; G1CollectedHeap* _g1;
size_t _freed_bytes; size_t _freed_bytes;
@ -1613,26 +1248,13 @@ void G1ConcurrentMark::cleanup() {
HeapRegionRemSet::reset_for_cleanup_tasks(); HeapRegionRemSet::reset_for_cleanup_tasks();
{ {
// Finalize the live data. GCTraceTime(Debug, gc)("Finalize Live Data");
G1FinalizeLiveDataTask cl(_nextMarkBitMap, finalize_live_data();
&_region_live_bm,
&_card_live_bm,
g1h->workers()->active_workers());
g1h->workers()->run_task(&cl);
} }
if (VerifyDuringGC) { if (VerifyDuringGC) {
// Verify that the liveness count data created concurrently matches one created GCTraceTime(Debug, gc)("Verify Live Data");
// during this safepoint. verify_live_data();
ResourceMark rm;
G1VerifyLiveDataTask cl(G1CollectedHeap::heap(),
_nextMarkBitMap,
&_region_live_bm,
&_card_live_bm,
g1h->workers()->active_workers());
g1h->workers()->run_task(&cl);
guarantee(cl.failures() == 0, "Unexpected accounting failures");
} }
g1h->collector_state()->set_mark_in_progress(false); g1h->collector_state()->set_mark_in_progress(false);
@ -1669,7 +1291,7 @@ void G1ConcurrentMark::cleanup() {
// regions. // regions.
if (G1ScrubRemSets) { if (G1ScrubRemSets) {
double rs_scrub_start = os::elapsedTime(); double rs_scrub_start = os::elapsedTime();
g1h->scrub_rem_set(&_region_live_bm, &_card_live_bm); g1h->scrub_rem_set();
_total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start); _total_rs_scrub_time += (os::elapsedTime() - rs_scrub_start);
} }
@ -2115,35 +1737,6 @@ void G1ConcurrentMark::swapMarkBitMaps() {
_nextMarkBitMap = (G1CMBitMap*) temp; _nextMarkBitMap = (G1CMBitMap*) temp;
} }
BitMap G1ConcurrentMark::allocate_large_bitmap(BitMap::idx_t size_in_bits) {
size_t size_in_words = BitMap::size_in_words(size_in_bits);
BitMap::bm_word_t* map = MmapArrayAllocator<BitMap::bm_word_t, mtGC>::allocate(size_in_words);
return BitMap(map, size_in_bits);
}
void G1ConcurrentMark::allocate_internal_bitmaps() {
double start_time = os::elapsedTime();
_region_live_bm = allocate_large_bitmap(_g1h->max_regions());
guarantee(_g1h->max_capacity() % CardTableModRefBS::card_size == 0,
"Heap capacity must be aligned to card size.");
_card_live_bm = allocate_large_bitmap(_g1h->max_capacity() / CardTableModRefBS::card_size);
log_debug(gc, marking)("Allocating internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time);
}
void G1ConcurrentMark::pretouch_internal_bitmaps() {
double start_time = os::elapsedTime();
_region_live_bm.pretouch();
_card_live_bm.pretouch();
log_debug(gc, marking)("Pre-touching internal bitmaps took %1.2f seconds.", os::elapsedTime() - start_time);
}
// Closure for marking entries in SATB buffers. // Closure for marking entries in SATB buffers.
class G1CMSATBBufferClosure : public SATBBufferClosure { class G1CMSATBBufferClosure : public SATBBufferClosure {
private: private:
@ -2403,120 +1996,28 @@ void G1ConcurrentMark::verify_no_cset_oops() {
} }
} }
#endif // PRODUCT #endif // PRODUCT
class G1CreateLiveDataTask: public AbstractGangTask {
// Aggregate the counting data that was constructed concurrently
// with marking.
class G1CreateLiveDataHRClosure: public HeapRegionClosure {
G1LiveDataHelper _helper;
G1CMBitMap* _mark_bitmap;
G1ConcurrentMark* _cm;
public:
G1CreateLiveDataHRClosure(G1ConcurrentMark* cm,
G1CMBitMap* mark_bitmap,
BitMap* cm_card_bm) :
HeapRegionClosure(),
_helper(NULL, cm_card_bm),
_mark_bitmap(mark_bitmap),
_cm(cm) { }
bool doHeapRegion(HeapRegion* hr) {
size_t marked_bytes = _helper.mark_marked_during_marking(_mark_bitmap, hr);
if (marked_bytes > 0) {
hr->add_to_marked_bytes(marked_bytes);
}
if (_cm->do_yield_check() && _cm->has_aborted()) {
return true;
}
return false;
}
};
G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm;
BitMap* _cm_card_bm;
HeapRegionClaimer _hr_claimer;
public:
G1CreateLiveDataTask(G1CollectedHeap* g1h,
BitMap* cm_card_bm,
uint n_workers) :
AbstractGangTask("Create Live Data"),
_g1h(g1h),
_cm_card_bm(cm_card_bm),
_hr_claimer(n_workers) {
}
void work(uint worker_id) {
SuspendibleThreadSetJoiner sts_join;
G1CreateLiveDataHRClosure cl(_g1h->concurrent_mark(), _g1h->concurrent_mark()->nextMarkBitMap(), _cm_card_bm);
_g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer);
}
};
void G1ConcurrentMark::create_live_data() { void G1ConcurrentMark::create_live_data() {
uint n_workers = _parallel_workers->active_workers(); _g1h->g1_rem_set()->create_card_live_data(_parallel_workers, _nextMarkBitMap);
G1CreateLiveDataTask cl(_g1h,
&_card_live_bm,
n_workers);
_parallel_workers->run_task(&cl);
} }
class G1ClearAllLiveDataTask : public AbstractGangTask { void G1ConcurrentMark::finalize_live_data() {
BitMap* _bitmap; _g1h->g1_rem_set()->finalize_card_live_data(_g1h->workers(), _nextMarkBitMap);
size_t _num_tasks;
size_t _cur_task;
public:
G1ClearAllLiveDataTask(BitMap* bitmap, size_t num_tasks) :
AbstractGangTask("Clear All Live Data"),
_bitmap(bitmap),
_num_tasks(num_tasks),
_cur_task(0) {
}
virtual void work(uint worker_id) {
while (true) {
size_t to_process = Atomic::add(1, &_cur_task) - 1;
if (to_process >= _num_tasks) {
break;
}
BitMap::idx_t start = M * BitsPerByte * to_process;
BitMap::idx_t end = MIN2(start + M * BitsPerByte, _bitmap->size());
_bitmap->clear_range(start, end);
}
}
};
void G1ConcurrentMark::clear_all_live_data(WorkGang* workers) {
double start_time = os::elapsedTime();
guarantee(Universe::is_fully_initialized(), "Should not call this during initialization.");
size_t const num_chunks = align_size_up(_card_live_bm.size_in_words() * HeapWordSize, M) / M;
G1ClearAllLiveDataTask cl(&_card_live_bm, num_chunks);
workers->run_task(&cl);
// The region live bitmap is always very small, even for huge heaps. Clear
// directly.
_region_live_bm.clear();
log_debug(gc, marking)("Clear Live Data took %.3fms", (os::elapsedTime() - start_time) * 1000.0);
} }
void G1ConcurrentMark::verify_all_live_data() { void G1ConcurrentMark::verify_live_data() {
assert(_card_live_bm.count_one_bits() == 0, "Master card bitmap not clear"); _g1h->g1_rem_set()->verify_card_live_data(_g1h->workers(), _nextMarkBitMap);
assert(_region_live_bm.count_one_bits() == 0, "Master region bitmap not clear");
} }
void G1ConcurrentMark::clear_live_data(WorkGang* workers) {
_g1h->g1_rem_set()->clear_card_live_data(workers);
}
#ifdef ASSERT
void G1ConcurrentMark::verify_live_data_clear() {
_g1h->g1_rem_set()->verify_card_live_data_is_clear();
}
#endif
void G1ConcurrentMark::print_stats() { void G1ConcurrentMark::print_stats() {
if (!log_is_enabled(Debug, gc, stats)) { if (!log_is_enabled(Debug, gc, stats)) {
return; return;
@ -2536,14 +2037,22 @@ void G1ConcurrentMark::abort() {
// Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next // Clear all marks in the next bitmap for the next marking cycle. This will allow us to skip the next
// concurrent bitmap clearing. // concurrent bitmap clearing.
clear_bitmap(_nextMarkBitMap, _g1h->workers(), false); {
GCTraceTime(Debug, gc)("Clear Next Bitmap");
clear_bitmap(_nextMarkBitMap, _g1h->workers(), false);
}
// Note we cannot clear the previous marking bitmap here // Note we cannot clear the previous marking bitmap here
// since VerifyDuringGC verifies the objects marked during // since VerifyDuringGC verifies the objects marked during
// a full GC against the previous bitmap. // a full GC against the previous bitmap.
clear_all_live_data(_g1h->workers()); {
DEBUG_ONLY(verify_all_live_data()); GCTraceTime(Debug, gc)("Clear Live Data");
clear_live_data(_g1h->workers());
}
DEBUG_ONLY({
GCTraceTime(Debug, gc)("Verify Live Data Clear");
verify_live_data_clear();
})
// Empty mark stack // Empty mark stack
reset_marking_state(); reset_marking_state();
for (uint i = 0; i < _max_worker_id; ++i) { for (uint i = 0; i < _max_worker_id; ++i) {
@ -2610,16 +2119,6 @@ void G1ConcurrentMark::print_on_error(outputStream* st) const {
_nextMarkBitMap->print_on_error(st, " Next Bits: "); _nextMarkBitMap->print_on_error(st, " Next Bits: ");
} }
// We take a break if someone is trying to stop the world.
bool G1ConcurrentMark::do_yield_check(uint worker_id) {
if (SuspendibleThreadSet::should_yield()) {
SuspendibleThreadSet::yield();
return true;
} else {
return false;
}
}
// Closure for iteration over bitmaps // Closure for iteration over bitmaps
class G1CMBitMapClosure : public BitMapClosure { class G1CMBitMapClosure : public BitMapClosure {
private: private:

View file

@ -298,15 +298,6 @@ protected:
G1CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap G1CMBitMapRO* _prevMarkBitMap; // Completed mark bitmap
G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap G1CMBitMap* _nextMarkBitMap; // Under-construction mark bitmap
// Liveness count data. After marking G1 iterates over the recently gathered mark
// bitmap and records rough information about liveness on card and region basis.
// This information can be used for e.g. remembered set scrubbing.
// A set bit indicates whether the given region contains any live object.
BitMap _region_live_bm;
// A set bit indicates that the given card contains a live object.
BitMap _card_live_bm;
// Heap bounds // Heap bounds
HeapWord* _heap_start; HeapWord* _heap_start;
HeapWord* _heap_end; HeapWord* _heap_end;
@ -379,14 +370,6 @@ protected:
void swapMarkBitMaps(); void swapMarkBitMaps();
// Allocates and returns a zero-ed out "large" bitmap of the given size in bits.
// It is always allocated using virtual memory.
BitMap allocate_large_bitmap(BitMap::idx_t size_in_bits);
// Allocates the memory for all bitmaps used by the concurrent marking.
void allocate_internal_bitmaps();
// Pre-touches the internal bitmaps.
void pretouch_internal_bitmaps();
// It resets the global marking data structures, as well as the // It resets the global marking data structures, as well as the
// task local ones; should be called during initial mark. // task local ones; should be called during initial mark.
void reset(); void reset();
@ -592,7 +575,7 @@ public:
void scan_root_regions(); void scan_root_regions();
// Scan a single root region and mark everything reachable from it. // Scan a single root region and mark everything reachable from it.
void scanRootRegion(HeapRegion* hr, uint worker_id); void scanRootRegion(HeapRegion* hr);
// Do concurrent phase of marking, to a tentative transitive closure. // Do concurrent phase of marking, to a tentative transitive closure.
void mark_from_roots(); void mark_from_roots();
@ -628,7 +611,7 @@ public:
inline bool isPrevMarked(oop p) const; inline bool isPrevMarked(oop p) const;
inline bool do_yield_check(uint worker_i = 0); inline bool do_yield_check();
// Abandon current marking iteration due to a Full GC. // Abandon current marking iteration due to a Full GC.
void abort(); void abort();
@ -654,16 +637,19 @@ public:
private: private:
// Clear (Reset) all liveness count data. // Clear (Reset) all liveness count data.
void clear_all_live_data(WorkGang* workers); void clear_live_data(WorkGang* workers);
#ifdef ASSERT
// Verify all of the above data structures that they are in initial state. // Verify all of the above data structures that they are in initial state.
void verify_all_live_data(); void verify_live_data_clear();
#endif
// Aggregates the per-card liveness data based on the current marking. Also sets // Aggregates the per-card liveness data based on the current marking. Also sets
// the amount of marked bytes for each region. // the amount of marked bytes for each region.
void create_live_data(); void create_live_data();
// Verification routine void finalize_live_data();
void verify_live_data(); void verify_live_data();
}; };
@ -852,7 +838,7 @@ public:
// Grey the object by marking it. If not already marked, push it on // Grey the object by marking it. If not already marked, push it on
// the local queue if below the finger. // the local queue if below the finger.
// Precondition: obj is below region's NTAMS. // obj is below its region's NTAMS.
inline void make_reference_grey(oop obj); inline void make_reference_grey(oop obj);
// Grey the object (by calling make_grey_reference) if required, // Grey the object (by calling make_grey_reference) if required,

View file

@ -27,6 +27,7 @@
#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1ConcurrentMark.hpp" #include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/suspendibleThreadSet.hpp"
#include "gc/shared/taskqueue.inline.hpp" #include "gc/shared/taskqueue.inline.hpp"
inline bool G1ConcurrentMark::par_mark(oop obj) { inline bool G1ConcurrentMark::par_mark(oop obj) {
@ -258,4 +259,13 @@ inline void G1ConcurrentMark::grayRoot(oop obj, HeapRegion* hr) {
} }
} }
inline bool G1ConcurrentMark::do_yield_check() {
if (SuspendibleThreadSet::should_yield()) {
SuspendibleThreadSet::yield();
return true;
} else {
return false;
}
}
#endif // SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP #endif // SHARE_VM_GC_G1_G1CONCURRENTMARK_INLINE_HPP

View file

@ -186,11 +186,9 @@ class G1RootRegionScanClosure : public MetadataAwareOopClosure {
private: private:
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm; G1ConcurrentMark* _cm;
uint _worker_id;
public: public:
G1RootRegionScanClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm, G1RootRegionScanClosure(G1CollectedHeap* g1h, G1ConcurrentMark* cm) :
uint worker_id) : _g1h(g1h), _cm(cm) { }
_g1h(g1h), _cm(cm), _worker_id(worker_id) { }
template <class T> void do_oop_nv(T* p); template <class T> void do_oop_nv(T* p);
virtual void do_oop( oop* p) { do_oop_nv(p); } virtual void do_oop( oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); }

View file

@ -38,6 +38,7 @@
#include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/gcTraceTime.inline.hpp"
#include "memory/iterator.hpp" #include "memory/iterator.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
@ -84,8 +85,16 @@ uint G1RemSet::num_par_rem_sets() {
return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads); return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads);
} }
void G1RemSet::initialize(uint max_regions) { void G1RemSet::initialize(size_t capacity, uint max_regions) {
G1FromCardCache::initialize(num_par_rem_sets(), max_regions); G1FromCardCache::initialize(num_par_rem_sets(), max_regions);
{
GCTraceTime(Debug, gc, marking)("Initialize Card Live Data");
_card_live_data.initialize(capacity, max_regions);
}
if (G1PretouchAuxiliaryMemory) {
GCTraceTime(Debug, gc, marking)("Pre-Touch Card Live Data");
_card_live_data.pretouch();
}
} }
ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc, ScanRSClosure::ScanRSClosure(G1ParPushHeapRSClosure* oc,
@ -312,27 +321,24 @@ void G1RemSet::cleanup_after_oops_into_collection_set_do() {
_into_cset_dirty_card_queue_set.clear_n_completed_buffers(); _into_cset_dirty_card_queue_set.clear_n_completed_buffers();
} }
class ScrubRSClosure: public HeapRegionClosure { class G1ScrubRSClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
BitMap* _region_bm; G1CardLiveData* _live_data;
BitMap* _card_bm;
CardTableModRefBS* _ctbs;
public: public:
ScrubRSClosure(BitMap* region_bm, BitMap* card_bm) : G1ScrubRSClosure(G1CardLiveData* live_data) :
_g1h(G1CollectedHeap::heap()), _g1h(G1CollectedHeap::heap()),
_region_bm(region_bm), _card_bm(card_bm), _live_data(live_data) { }
_ctbs(_g1h->g1_barrier_set()) {}
bool doHeapRegion(HeapRegion* r) { bool doHeapRegion(HeapRegion* r) {
if (!r->is_continues_humongous()) { if (!r->is_continues_humongous()) {
r->rem_set()->scrub(_ctbs, _region_bm, _card_bm); r->rem_set()->scrub(_live_data);
} }
return false; return false;
} }
}; };
void G1RemSet::scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer *hrclaimer) { void G1RemSet::scrub(uint worker_num, HeapRegionClaimer *hrclaimer) {
ScrubRSClosure scrub_cl(region_bm, card_bm); G1ScrubRSClosure scrub_cl(&_card_live_data);
_g1->heap_region_par_iterate(&scrub_cl, worker_num, hrclaimer); _g1->heap_region_par_iterate(&scrub_cl, worker_num, hrclaimer);
} }
@ -580,3 +586,25 @@ void G1RemSet::prepare_for_verify() {
assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); assert(JavaThread::dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed");
} }
} }
void G1RemSet::create_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap) {
_card_live_data.create(workers, mark_bitmap);
}
void G1RemSet::finalize_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap) {
_card_live_data.finalize(workers, mark_bitmap);
}
void G1RemSet::verify_card_live_data(WorkGang* workers, G1CMBitMap* bitmap) {
_card_live_data.verify(workers, bitmap);
}
void G1RemSet::clear_card_live_data(WorkGang* workers) {
_card_live_data.clear(workers);
}
#ifdef ASSERT
void G1RemSet::verify_card_live_data_is_clear() {
_card_live_data.verify_is_clear();
}
#endif

View file

@ -26,6 +26,7 @@
#define SHARE_VM_GC_G1_G1REMSET_HPP #define SHARE_VM_GC_G1_G1REMSET_HPP
#include "gc/g1/dirtyCardQueue.hpp" #include "gc/g1/dirtyCardQueue.hpp"
#include "gc/g1/g1CardLiveData.hpp"
#include "gc/g1/g1RemSetSummary.hpp" #include "gc/g1/g1RemSetSummary.hpp"
#include "gc/g1/heapRegion.hpp" #include "gc/g1/heapRegion.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
@ -48,9 +49,10 @@ class HeapRegionClaimer;
// A G1RemSet in which each heap region has a rem set that records the // A G1RemSet in which each heap region has a rem set that records the
// external heap references into it. Uses a mod ref bs to track updates, // external heap references into it. Uses a mod ref bs to track updates,
// so that they can be used to update the individual region remsets. // so that they can be used to update the individual region remsets.
class G1RemSet: public CHeapObj<mtGC> { class G1RemSet: public CHeapObj<mtGC> {
private: private:
G1CardLiveData _card_live_data;
G1RemSetSummary _prev_period_summary; G1RemSetSummary _prev_period_summary;
// A DirtyCardQueueSet that is used to hold cards that contain // A DirtyCardQueueSet that is used to hold cards that contain
@ -83,7 +85,7 @@ public:
static uint num_par_rem_sets(); static uint num_par_rem_sets();
// Initialize data that depends on the heap size being known. // Initialize data that depends on the heap size being known.
static void initialize(uint max_regions); void initialize(size_t capacity, uint max_regions);
// This is called to reset dual hash tables after the gc pause // This is called to reset dual hash tables after the gc pause
// is finished and the initial hash table is no longer being // is finished and the initial hash table is no longer being
@ -140,7 +142,7 @@ public:
// set entries that correspond to dead heap ranges. "worker_num" is the // set entries that correspond to dead heap ranges. "worker_num" is the
// parallel thread id of the current thread, and "hrclaimer" is the // parallel thread id of the current thread, and "hrclaimer" is the
// HeapRegionClaimer that should be used. // HeapRegionClaimer that should be used.
void scrub(BitMap* region_bm, BitMap* card_bm, uint worker_num, HeapRegionClaimer* hrclaimer); void scrub(uint worker_num, HeapRegionClaimer* hrclaimer);
// Refine the card corresponding to "card_ptr". // Refine the card corresponding to "card_ptr".
// If check_for_refs_into_cset is true, a true result is returned // If check_for_refs_into_cset is true, a true result is returned
@ -162,6 +164,19 @@ public:
size_t conc_refine_cards() const { size_t conc_refine_cards() const {
return _conc_refine_cards; return _conc_refine_cards;
} }
void create_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap);
void finalize_card_live_data(WorkGang* workers, G1CMBitMap* mark_bitmap);
// Verify that the liveness count data created concurrently matches one created
// during this safepoint.
void verify_card_live_data(WorkGang* workers, G1CMBitMap* actual_bitmap);
void clear_card_live_data(WorkGang* workers);
#ifdef ASSERT
void verify_card_live_data_is_clear();
#endif
}; };
class ScanRSClosure : public HeapRegionClosure { class ScanRSClosure : public HeapRegionClosure {

View file

@ -26,6 +26,7 @@
#include "gc/g1/concurrentG1Refine.hpp" #include "gc/g1/concurrentG1Refine.hpp"
#include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1BlockOffsetTable.inline.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1CardLiveData.inline.hpp"
#include "gc/g1/heapRegionManager.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionRemSet.hpp"
#include "gc/shared/space.inline.hpp" #include "gc/shared/space.inline.hpp"
@ -141,10 +142,8 @@ public:
add_reference_work(from, /*parallel*/ false); add_reference_work(from, /*parallel*/ false);
} }
void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) { void scrub(G1CardLiveData* live_data) {
HeapWord* hr_bot = hr()->bottom(); live_data->remove_nonlive_cards(hr()->hrm_index(), &_bm);
size_t hr_first_card_index = ctbs->index_for(hr_bot);
bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
recount_occupied(); recount_occupied();
} }
@ -515,14 +514,12 @@ PerRegionTable* OtherRegionsTable::delete_region_table() {
return max; return max;
} }
void OtherRegionsTable::scrub(CardTableModRefBS* ctbs, void OtherRegionsTable::scrub(G1CardLiveData* live_data) {
BitMap* region_bm, BitMap* card_bm) {
// First eliminated garbage regions from the coarse map. // First eliminated garbage regions from the coarse map.
log_develop_trace(gc, remset, scrub)("Scrubbing region %u:", _hr->hrm_index()); log_develop_trace(gc, remset, scrub)("Scrubbing region %u:", _hr->hrm_index());
assert(_coarse_map.size() == region_bm->size(), "Precondition");
log_develop_trace(gc, remset, scrub)(" Coarse map: before = " SIZE_FORMAT "...", _n_coarse_entries); log_develop_trace(gc, remset, scrub)(" Coarse map: before = " SIZE_FORMAT "...", _n_coarse_entries);
_coarse_map.set_intersection(*region_bm); live_data->remove_nonlive_regions(&_coarse_map);
_n_coarse_entries = _coarse_map.count_one_bits(); _n_coarse_entries = _coarse_map.count_one_bits();
log_develop_trace(gc, remset, scrub)(" after = " SIZE_FORMAT ".", _n_coarse_entries); log_develop_trace(gc, remset, scrub)(" after = " SIZE_FORMAT ".", _n_coarse_entries);
@ -534,7 +531,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
PerRegionTable* nxt = cur->collision_list_next(); PerRegionTable* nxt = cur->collision_list_next();
// If the entire region is dead, eliminate. // If the entire region is dead, eliminate.
log_develop_trace(gc, remset, scrub)(" For other region %u:", cur->hr()->hrm_index()); log_develop_trace(gc, remset, scrub)(" For other region %u:", cur->hr()->hrm_index());
if (!region_bm->at((size_t) cur->hr()->hrm_index())) { if (!live_data->is_region_live(cur->hr()->hrm_index())) {
*prev = nxt; *prev = nxt;
cur->set_collision_list_next(NULL); cur->set_collision_list_next(NULL);
_n_fine_entries--; _n_fine_entries--;
@ -544,7 +541,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
} else { } else {
// Do fine-grain elimination. // Do fine-grain elimination.
log_develop_trace(gc, remset, scrub)(" occ: before = %4d.", cur->occupied()); log_develop_trace(gc, remset, scrub)(" occ: before = %4d.", cur->occupied());
cur->scrub(ctbs, card_bm); cur->scrub(live_data);
log_develop_trace(gc, remset, scrub)(" after = %4d.", cur->occupied()); log_develop_trace(gc, remset, scrub)(" after = %4d.", cur->occupied());
// Did that empty the table completely? // Did that empty the table completely?
if (cur->occupied() == 0) { if (cur->occupied() == 0) {
@ -773,9 +770,8 @@ void HeapRegionRemSet::reset_for_par_iteration() {
assert(verify_ready_for_par_iteration(), "post-condition"); assert(verify_ready_for_par_iteration(), "post-condition");
} }
void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs, void HeapRegionRemSet::scrub(G1CardLiveData* live_data) {
BitMap* region_bm, BitMap* card_bm) { _other_regions.scrub(live_data);
_other_regions.scrub(ctbs, region_bm, card_bm);
} }
// Code roots support // Code roots support

View file

@ -35,6 +35,7 @@
class G1CollectedHeap; class G1CollectedHeap;
class G1BlockOffsetTable; class G1BlockOffsetTable;
class G1CardLiveData;
class HeapRegion; class HeapRegion;
class HeapRegionRemSetIterator; class HeapRegionRemSetIterator;
class PerRegionTable; class PerRegionTable;
@ -143,7 +144,7 @@ public:
// Removes any entries shown by the given bitmaps to contain only dead // Removes any entries shown by the given bitmaps to contain only dead
// objects. Not thread safe. // objects. Not thread safe.
// Set bits in the bitmaps indicate that the given region or card is live. // Set bits in the bitmaps indicate that the given region or card is live.
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); void scrub(G1CardLiveData* live_data);
// Returns whether this remembered set (and all sub-sets) does not contain any entry. // Returns whether this remembered set (and all sub-sets) does not contain any entry.
bool is_empty() const; bool is_empty() const;
@ -230,10 +231,9 @@ public:
_other_regions.add_reference(from, tid); _other_regions.add_reference(from, tid);
} }
// Removes any entries in the remembered set shown by the given bitmaps to // Removes any entries in the remembered set shown by the given card live data to
// contain only dead objects. Not thread safe. // contain only dead objects. Not thread safe.
// One bits in the bitmaps indicate that the given region or card is live. void scrub(G1CardLiveData* live_data);
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
// The region is being reclaimed; clear its remset, and any mention of // The region is being reclaimed; clear its remset, and any mention of
// entries for this region in other remsets. // entries for this region in other remsets.

View file

@ -69,7 +69,7 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) {
} }
void BitMap::pretouch() { void BitMap::pretouch() {
os::pretouch_memory((char*)word_addr(0), (char*)word_addr(size())); os::pretouch_memory(word_addr(0), word_addr(size()));
} }
void BitMap::set_range_within_word(idx_t beg, idx_t end) { void BitMap::set_range_within_word(idx_t beg, idx_t end) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -140,11 +140,12 @@ class BitMap VALUE_OBJ_CLASS_SPEC {
// Accessing // Accessing
idx_t size() const { return _size; } idx_t size() const { return _size; }
idx_t size_in_bytes() const { return size_in_words() * BytesPerWord; }
idx_t size_in_words() const { idx_t size_in_words() const {
return word_index(size() + BitsPerWord - 1); return calc_size_in_words(size());
} }
static idx_t size_in_words(size_t size_in_bits) { static idx_t calc_size_in_words(size_t size_in_bits) {
return word_index(size_in_bits + BitsPerWord - 1); return word_index(size_in_bits + BitsPerWord - 1);
} }