8267924: Misleading G1 eager reclaim detail logging

Reviewed-by: ayang, sjohanss
This commit is contained in:
Thomas Schatzl 2021-06-07 13:18:27 +00:00
parent e4d045402f
commit 15715a8984
3 changed files with 57 additions and 59 deletions

@ -3391,6 +3391,16 @@ class G1PrepareEvacuationTask : public AbstractGangTask {
_g1h->set_humongous_reclaim_candidate(index, false);
_g1h->register_region_with_region_attr(hr);
}
log_debug(gc, humongous)("Humongous region %u (object size " SIZE_FORMAT " @ " PTR_FORMAT ") remset " SIZE_FORMAT " code roots " SIZE_FORMAT " marked %d reclaim candidate %d type array %d",
index,
(size_t)cast_to_oop(hr->bottom())->size() * HeapWordSize,
p2i(hr->bottom()),
hr->rem_set()->occupied(),
hr->rem_set()->strong_code_roots_list_length(),
_g1h->concurrent_mark()->next_mark_bitmap()->is_marked(hr->bottom()),
_g1h->is_humongous_reclaim_candidate(index),
cast_to_oop(hr->bottom())->is_typeArray()
);
_worker_humongous_total++;
return false;

@ -91,8 +91,43 @@ class G1FreeHumongousRegionClosure : public HeapRegionClosure {
uint _humongous_objects_reclaimed;
uint _humongous_regions_reclaimed;
size_t _freed_bytes;
public:
// Returns whether the given humongous object defined by the start region index
// is reclaimable.
//
// At this point in the garbage collection, checking whether the humongous object
// is still a candidate is sufficient because:
//
// - if it has not been a candidate at the start of collection, it will never
// changed to be a candidate during the gc (and live).
// - any found outstanding (i.e. in the DCQ, or in its remembered set)
// references will set the candidate state to false.
// - there can be no references from within humongous starts regions referencing
// the object because we never allocate other objects into them.
// (I.e. there can be no intra-region references)
//
// It is not required to check whether the object has been found dead by marking
// or not, in fact it would prevent reclamation within a concurrent cycle, as
// all objects allocated during that time are considered live.
// SATB marking is even more conservative than the remembered set.
// So if at this point in the collection we did not find a reference during gc
// (or it had enough references to not be a candidate, having many remembered
// set entries), nobody has a reference to it.
// At the start of collection we flush all refinement logs, and remembered sets
// are completely up-to-date wrt to references to the humongous object.
//
// So there is no need to re-check remembered set size of the humongous region.
//
// Other implementation considerations:
// - never consider object arrays at this time because they would pose
// considerable effort for cleaning up the the remembered sets. This is
// required because stale remembered sets might reference locations that
// are currently allocated into.
bool is_reclaimable(uint region_idx) const {
return G1CollectedHeap::heap()->is_humongous_reclaim_candidate(region_idx);
}
public:
G1FreeHumongousRegionClosure() :
_humongous_objects_reclaimed(0),
_humongous_regions_reclaimed(0),
@ -104,70 +139,17 @@ public:
return false;
}
G1CollectedHeap* g1h = G1CollectedHeap::heap();
oop obj = cast_to_oop(r->bottom());
G1CMBitMap* next_bitmap = g1h->concurrent_mark()->next_mark_bitmap();
// The following checks whether the humongous object is live are sufficient.
// The main additional check (in addition to having a reference from the roots
// or the young gen) is whether the humongous object has a remembered set entry.
//
// A humongous object cannot be live if there is no remembered set for it
// because:
// - there can be no references from within humongous starts regions referencing
// the object because we never allocate other objects into them.
// (I.e. there are no intra-region references that may be missed by the
// remembered set)
// - as soon there is a remembered set entry to the humongous starts region
// (i.e. it has "escaped" to an old object) this remembered set entry will stay
// until the end of a concurrent mark.
//
// It is not required to check whether the object has been found dead by marking
// or not, in fact it would prevent reclamation within a concurrent cycle, as
// all objects allocated during that time are considered live.
// SATB marking is even more conservative than the remembered set.
// So if at this point in the collection there is no remembered set entry,
// nobody has a reference to it.
// At the start of collection we flush all refinement logs, and remembered sets
// are completely up-to-date wrt to references to the humongous object.
//
// Other implementation considerations:
// - never consider object arrays at this time because they would pose
// considerable effort for cleaning up the the remembered sets. This is
// required because stale remembered sets might reference locations that
// are currently allocated into.
uint region_idx = r->hrm_index();
if (!g1h->is_humongous_reclaim_candidate(region_idx) ||
!r->rem_set()->is_empty()) {
log_debug(gc, humongous)("Live humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
region_idx,
(size_t)obj->size() * HeapWordSize,
p2i(r->bottom()),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->is_marked(r->bottom()),
g1h->is_humongous_reclaim_candidate(region_idx),
obj->is_typeArray()
);
if (!is_reclaimable(region_idx)) {
return false;
}
oop obj = cast_to_oop(r->bottom());
guarantee(obj->is_typeArray(),
"Only eagerly reclaiming type arrays is supported, but the object "
PTR_FORMAT " is not.", p2i(r->bottom()));
log_debug(gc, humongous)("Dead humongous region %u object size " SIZE_FORMAT " start " PTR_FORMAT " with remset " SIZE_FORMAT " code roots " SIZE_FORMAT " is marked %d reclaim candidate %d type array %d",
region_idx,
(size_t)obj->size() * HeapWordSize,
p2i(r->bottom()),
r->rem_set()->occupied(),
r->rem_set()->strong_code_roots_list_length(),
next_bitmap->is_marked(r->bottom()),
g1h->is_humongous_reclaim_candidate(region_idx),
obj->is_typeArray()
);
G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1ConcurrentMark* const cm = g1h->concurrent_mark();
cm->humongous_object_eagerly_reclaimed(r);
assert(!cm->is_marked_in_prev_bitmap(obj) && !cm->is_marked_in_next_bitmap(obj),
@ -186,6 +168,11 @@ public:
r = next;
} while (r != nullptr);
log_debug(gc, humongous)("Reclaimed humongous region %u (object size " SIZE_FORMAT " @ " PTR_FORMAT ")",
region_idx,
(size_t)obj->size() * HeapWordSize,
p2i(r->bottom())
);
return false;
}

@ -52,6 +52,7 @@ public class TestG1TraceEagerReclaimHumongousObjects {
OutputAnalyzer output = new OutputAnalyzer(pb.start());
System.out.println(output.getStdout());
// As G1ReclaimDeadHumongousObjectsAtYoungGC is set(default), below logs should be displayed.
output.shouldContain("Humongous Reclaim");
output.shouldContain("Humongous Total");
@ -60,8 +61,8 @@ public class TestG1TraceEagerReclaimHumongousObjects {
// As G1TraceReclaimDeadHumongousObjectsAtYoungGC is set and GCWithHumongousObjectTest has humongous objects,
// these logs should be displayed.
output.shouldContain("Live humongous");
output.shouldContain("Dead humongous region");
output.shouldContain("Humongous region");
output.shouldContain("Reclaimed humongous region");
output.shouldHaveExitValue(0);
}