mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-22 03:54:33 +02:00
8038423: G1: Decommit memory within heap
Allow G1 to decommit memory of arbitrary regions within the heap and their associated auxiliary data structures card table, BOT, hot card cache, and mark bitmaps. Reviewed-by: mgerdin, brutisso, jwilhelm
This commit is contained in:
parent
2617d54723
commit
100e51a339
32 changed files with 1322 additions and 579 deletions
|
@ -33,31 +33,26 @@
|
|||
|
||||
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
|
||||
|
||||
void G1CardCountsMappingChangedListener::on_commit(uint start_idx, size_t num_regions) {
|
||||
MemRegion mr(G1CollectedHeap::heap()->bottom_addr_for_region(start_idx), num_regions * HeapRegion::GrainWords);
|
||||
_counts->clear_range(mr);
|
||||
}
|
||||
|
||||
void G1CardCounts::clear_range(size_t from_card_num, size_t to_card_num) {
|
||||
if (has_count_table()) {
|
||||
assert(from_card_num >= 0 && from_card_num < _committed_max_card_num,
|
||||
err_msg("from card num out of range: "SIZE_FORMAT, from_card_num));
|
||||
assert(from_card_num < to_card_num,
|
||||
err_msg("Wrong order? from: " SIZE_FORMAT ", to: "SIZE_FORMAT,
|
||||
from_card_num, to_card_num));
|
||||
assert(to_card_num <= _committed_max_card_num,
|
||||
err_msg("to card num out of range: "
|
||||
"to: "SIZE_FORMAT ", "
|
||||
"max: "SIZE_FORMAT,
|
||||
to_card_num, _committed_max_card_num));
|
||||
|
||||
to_card_num = MIN2(_committed_max_card_num, to_card_num);
|
||||
|
||||
Copy::fill_to_bytes(&_card_counts[from_card_num], (to_card_num - from_card_num));
|
||||
}
|
||||
}
|
||||
|
||||
G1CardCounts::G1CardCounts(G1CollectedHeap *g1h):
|
||||
_g1h(g1h), _card_counts(NULL),
|
||||
_reserved_max_card_num(0), _committed_max_card_num(0),
|
||||
_committed_size(0) {}
|
||||
_listener(), _g1h(g1h), _card_counts(NULL), _reserved_max_card_num(0) {
|
||||
_listener.set_cardcounts(this);
|
||||
}
|
||||
|
||||
void G1CardCounts::initialize() {
|
||||
void G1CardCounts::initialize(G1RegionToSpaceMapper* mapper) {
|
||||
assert(_g1h->max_capacity() > 0, "initialization order");
|
||||
assert(_g1h->capacity() == 0, "initialization order");
|
||||
|
||||
|
@ -70,70 +65,9 @@ void G1CardCounts::initialize() {
|
|||
_ct_bs = _g1h->g1_barrier_set();
|
||||
_ct_bot = _ct_bs->byte_for_const(_g1h->reserved_region().start());
|
||||
|
||||
// Allocate/Reserve the counts table
|
||||
size_t reserved_bytes = _g1h->max_capacity();
|
||||
_reserved_max_card_num = reserved_bytes >> CardTableModRefBS::card_shift;
|
||||
|
||||
size_t reserved_size = _reserved_max_card_num * sizeof(jbyte);
|
||||
ReservedSpace rs(ReservedSpace::allocation_align_size_up(reserved_size));
|
||||
if (!rs.is_reserved()) {
|
||||
warning("Could not reserve enough space for the card counts table");
|
||||
guarantee(!has_reserved_count_table(), "should be NULL");
|
||||
return;
|
||||
}
|
||||
|
||||
MemTracker::record_virtual_memory_type((address)rs.base(), mtGC);
|
||||
|
||||
_card_counts_storage.initialize(rs, 0);
|
||||
_card_counts = (jubyte*) _card_counts_storage.low();
|
||||
}
|
||||
}
|
||||
|
||||
void G1CardCounts::resize(size_t heap_capacity) {
|
||||
// Expand the card counts table to handle a heap with the given capacity.
|
||||
|
||||
if (!has_reserved_count_table()) {
|
||||
// Don't expand if we failed to reserve the card counts table.
|
||||
return;
|
||||
}
|
||||
|
||||
assert(_committed_size ==
|
||||
ReservedSpace::allocation_align_size_up(_committed_size),
|
||||
err_msg("Unaligned? committed_size: " SIZE_FORMAT, _committed_size));
|
||||
|
||||
// Verify that the committed space for the card counts matches our
|
||||
// committed max card num. Note for some allocation alignments, the
|
||||
// amount of space actually committed for the counts table will be able
|
||||
// to span more cards than the number spanned by the maximum heap.
|
||||
size_t prev_committed_size = _committed_size;
|
||||
size_t prev_committed_card_num = committed_to_card_num(prev_committed_size);
|
||||
|
||||
assert(prev_committed_card_num == _committed_max_card_num,
|
||||
err_msg("Card mismatch: "
|
||||
"prev: " SIZE_FORMAT ", "
|
||||
"committed: "SIZE_FORMAT", "
|
||||
"reserved: "SIZE_FORMAT,
|
||||
prev_committed_card_num, _committed_max_card_num, _reserved_max_card_num));
|
||||
|
||||
size_t new_size = (heap_capacity >> CardTableModRefBS::card_shift) * sizeof(jbyte);
|
||||
size_t new_committed_size = ReservedSpace::allocation_align_size_up(new_size);
|
||||
size_t new_committed_card_num = committed_to_card_num(new_committed_size);
|
||||
|
||||
if (_committed_max_card_num < new_committed_card_num) {
|
||||
// we need to expand the backing store for the card counts
|
||||
size_t expand_size = new_committed_size - prev_committed_size;
|
||||
|
||||
if (!_card_counts_storage.expand_by(expand_size)) {
|
||||
warning("Card counts table backing store commit failure");
|
||||
return;
|
||||
}
|
||||
assert(_card_counts_storage.committed_size() == new_committed_size,
|
||||
"expansion commit failure");
|
||||
|
||||
_committed_size = new_committed_size;
|
||||
_committed_max_card_num = new_committed_card_num;
|
||||
|
||||
clear_range(prev_committed_card_num, _committed_max_card_num);
|
||||
_card_counts = (jubyte*) mapper->reserved().start();
|
||||
_reserved_max_card_num = mapper->reserved().byte_size();
|
||||
mapper->set_mapping_changed_listener(&_listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,12 +83,13 @@ uint G1CardCounts::add_card_count(jbyte* card_ptr) {
|
|||
uint count = 0;
|
||||
if (has_count_table()) {
|
||||
size_t card_num = ptr_2_card_num(card_ptr);
|
||||
if (card_num < _committed_max_card_num) {
|
||||
count = (uint) _card_counts[card_num];
|
||||
if (count < G1ConcRSHotCardLimit) {
|
||||
_card_counts[card_num] =
|
||||
(jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit));
|
||||
}
|
||||
assert(card_num < _reserved_max_card_num,
|
||||
err_msg("Card "SIZE_FORMAT" outside of card counts table (max size "SIZE_FORMAT")",
|
||||
card_num, _reserved_max_card_num));
|
||||
count = (uint) _card_counts[card_num];
|
||||
if (count < G1ConcRSHotCardLimit) {
|
||||
_card_counts[card_num] =
|
||||
(jubyte)(MIN2((uintx)(_card_counts[card_num] + 1), G1ConcRSHotCardLimit));
|
||||
}
|
||||
}
|
||||
return count;
|
||||
|
@ -165,31 +100,23 @@ bool G1CardCounts::is_hot(uint count) {
|
|||
}
|
||||
|
||||
void G1CardCounts::clear_region(HeapRegion* hr) {
|
||||
assert(!hr->isHumongous(), "Should have been cleared");
|
||||
MemRegion mr(hr->bottom(), hr->end());
|
||||
clear_range(mr);
|
||||
}
|
||||
|
||||
void G1CardCounts::clear_range(MemRegion mr) {
|
||||
if (has_count_table()) {
|
||||
HeapWord* bottom = hr->bottom();
|
||||
|
||||
// We use the last address in hr as hr could be the
|
||||
// last region in the heap. In which case trying to find
|
||||
// the card for hr->end() will be an OOB access to the
|
||||
// card table.
|
||||
HeapWord* last = hr->end() - 1;
|
||||
assert(_g1h->g1_committed().contains(last),
|
||||
err_msg("last not in committed: "
|
||||
"last: " PTR_FORMAT ", "
|
||||
"committed: [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
last,
|
||||
_g1h->g1_committed().start(),
|
||||
_g1h->g1_committed().end()));
|
||||
|
||||
const jbyte* from_card_ptr = _ct_bs->byte_for_const(bottom);
|
||||
const jbyte* last_card_ptr = _ct_bs->byte_for_const(last);
|
||||
const jbyte* from_card_ptr = _ct_bs->byte_for_const(mr.start());
|
||||
// We use the last address in the range as the range could represent the
|
||||
// last region in the heap. In which case trying to find the card will be an
|
||||
// OOB access to the card table.
|
||||
const jbyte* last_card_ptr = _ct_bs->byte_for_const(mr.last());
|
||||
|
||||
#ifdef ASSERT
|
||||
HeapWord* start_addr = _ct_bs->addr_for(from_card_ptr);
|
||||
assert(start_addr == hr->bottom(), "alignment");
|
||||
assert(start_addr == mr.start(), "MemRegion start must be aligned to a card.");
|
||||
HeapWord* last_addr = _ct_bs->addr_for(last_card_ptr);
|
||||
assert((last_addr + CardTableModRefBS::card_size_in_words) == hr->end(), "alignment");
|
||||
assert((last_addr + CardTableModRefBS::card_size_in_words) == mr.end(), "MemRegion end must be aligned to a card.");
|
||||
#endif // ASSERT
|
||||
|
||||
// Clear the counts for the (exclusive) card range.
|
||||
|
@ -199,14 +126,22 @@ void G1CardCounts::clear_region(HeapRegion* hr) {
|
|||
}
|
||||
}
|
||||
|
||||
class G1CardCountsClearClosure : public HeapRegionClosure {
|
||||
private:
|
||||
G1CardCounts* _card_counts;
|
||||
public:
|
||||
G1CardCountsClearClosure(G1CardCounts* card_counts) :
|
||||
HeapRegionClosure(), _card_counts(card_counts) { }
|
||||
|
||||
|
||||
virtual bool doHeapRegion(HeapRegion* r) {
|
||||
_card_counts->clear_region(r);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void G1CardCounts::clear_all() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "don't call this otherwise");
|
||||
clear_range((size_t)0, _committed_max_card_num);
|
||||
G1CardCountsClearClosure cl(this);
|
||||
_g1h->heap_region_iterate(&cl);
|
||||
}
|
||||
|
||||
G1CardCounts::~G1CardCounts() {
|
||||
if (has_reserved_count_table()) {
|
||||
_card_counts_storage.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue