8331557: Serial: Refactor SerialHeap::do_collection
Reviewed-by: gli, iwalulya
This commit is contained in:
parent
14198f502f
commit
f1ce9b0ecc
@ -641,22 +641,9 @@ void DefNewGeneration::adjust_desired_tenuring_threshold() {
|
||||
age_table()->print_age_table();
|
||||
}
|
||||
|
||||
void DefNewGeneration::collect(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab) {
|
||||
assert(full || size > 0, "otherwise we don't want to collect");
|
||||
|
||||
bool DefNewGeneration::collect(bool clear_all_soft_refs) {
|
||||
SerialHeap* heap = SerialHeap::heap();
|
||||
|
||||
// If the next generation is too full to accommodate promotion
|
||||
// from this generation, pass on collection; let the next generation
|
||||
// do it.
|
||||
if (!collection_attempt_is_safe()) {
|
||||
log_trace(gc)(":: Collection attempt not safe ::");
|
||||
heap->set_incremental_collection_failed(); // Slight lie: we did not even attempt one
|
||||
return;
|
||||
}
|
||||
assert(to()->is_empty(), "Else not collection_attempt_is_safe");
|
||||
_gc_timer->register_gc_start();
|
||||
_gc_tracer->report_gc_start(heap->gc_cause(), _gc_timer->gc_start());
|
||||
@ -774,6 +761,8 @@ void DefNewGeneration::collect(bool full,
|
||||
_gc_timer->register_gc_end();
|
||||
|
||||
_gc_tracer->report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
|
||||
|
||||
return !_promotion_failed;
|
||||
}
|
||||
|
||||
void DefNewGeneration::init_assuming_no_promotion_failure() {
|
||||
|
@ -208,19 +208,18 @@ class DefNewGeneration: public Generation {
|
||||
HeapWord* block_start(const void* p) const;
|
||||
|
||||
// Allocation support
|
||||
virtual bool should_allocate(size_t word_size, bool is_tlab) {
|
||||
bool should_allocate(size_t word_size, bool is_tlab) {
|
||||
assert(UseTLAB || !is_tlab, "Should not allocate tlab");
|
||||
assert(word_size != 0, "precondition");
|
||||
|
||||
size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize);
|
||||
|
||||
const bool non_zero = word_size > 0;
|
||||
const bool overflows = word_size >= overflow_limit;
|
||||
const bool check_too_big = _pretenure_size_threshold_words > 0;
|
||||
const bool not_too_big = word_size < _pretenure_size_threshold_words;
|
||||
const bool size_ok = is_tlab || !check_too_big || not_too_big;
|
||||
|
||||
bool result = !overflows &&
|
||||
non_zero &&
|
||||
size_ok;
|
||||
|
||||
return result;
|
||||
@ -253,10 +252,7 @@ class DefNewGeneration: public Generation {
|
||||
// at some additional cost.
|
||||
bool collection_attempt_is_safe();
|
||||
|
||||
virtual void collect(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab);
|
||||
bool collect(bool clear_all_soft_refs);
|
||||
|
||||
HeapWord* expand_and_allocate(size_t size, bool is_tlab);
|
||||
|
||||
|
@ -70,14 +70,3 @@ void Generation::print_on(outputStream* st) const {
|
||||
p2i(_virtual_space.high()),
|
||||
p2i(_virtual_space.high_boundary()));
|
||||
}
|
||||
|
||||
void Generation::print_summary_info_on(outputStream* st) {
|
||||
StatRecord* sr = stat_record();
|
||||
double time = sr->accumulated_time.seconds();
|
||||
st->print_cr("Accumulated %s generation GC time %3.7f secs, "
|
||||
"%u GC's, avg GC time %3.7f",
|
||||
SerialHeap::heap()->is_young_gen(this) ? "young" : "old" ,
|
||||
time,
|
||||
sr->invocations,
|
||||
sr->invocations > 0 ? time / sr->invocations : 0.0);
|
||||
}
|
||||
|
@ -107,20 +107,6 @@ class Generation: public CHeapObj<mtGC> {
|
||||
return _reserved.contains(p);
|
||||
}
|
||||
|
||||
// Returns "true" iff this generation should be used to allocate an
|
||||
// object of the given size. Young generations might
|
||||
// wish to exclude very large objects, for example, since, if allocated
|
||||
// often, they would greatly increase the frequency of young-gen
|
||||
// collection.
|
||||
virtual bool should_allocate(size_t word_size, bool is_tlab) {
|
||||
bool result = false;
|
||||
size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize);
|
||||
if (!is_tlab || supports_tlab_allocation()) {
|
||||
result = (word_size > 0) && (word_size < overflow_limit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Allocate and returns a block of the requested size, or returns "null".
|
||||
// Assumes the caller has done any necessary locking.
|
||||
virtual HeapWord* allocate(size_t word_size, bool is_tlab) = 0;
|
||||
@ -131,31 +117,6 @@ class Generation: public CHeapObj<mtGC> {
|
||||
// Thread-local allocation buffers
|
||||
virtual bool supports_tlab_allocation() const { return false; }
|
||||
|
||||
// Returns "true" iff collect() should subsequently be called on this
|
||||
// this generation. See comment below.
|
||||
// This is a generic implementation which can be overridden.
|
||||
//
|
||||
// Note: in the current (1.4) implementation, when serialHeap's
|
||||
// incremental_collection_will_fail flag is set, all allocations are
|
||||
// slow path (the only fast-path place to allocate is DefNew, which
|
||||
// will be full if the flag is set).
|
||||
// Thus, older generations which collect younger generations should
|
||||
// test this flag and collect if it is set.
|
||||
virtual bool should_collect(bool full,
|
||||
size_t word_size,
|
||||
bool is_tlab) {
|
||||
return (full || should_allocate(word_size, is_tlab));
|
||||
}
|
||||
|
||||
// Perform a garbage collection.
|
||||
// If full is true attempt a full garbage collection of this generation.
|
||||
// Otherwise, attempting to (at least) free enough space to support an
|
||||
// allocation of the given "word_size".
|
||||
virtual void collect(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t word_size,
|
||||
bool is_tlab) = 0;
|
||||
|
||||
// Perform a heap collection, attempting to create (at least) enough
|
||||
// space to support an allocation of the given "word_size". If
|
||||
// successful, perform the allocation and return the resulting
|
||||
@ -172,20 +133,7 @@ class Generation: public CHeapObj<mtGC> {
|
||||
|
||||
virtual void verify() = 0;
|
||||
|
||||
struct StatRecord {
|
||||
int invocations;
|
||||
elapsedTimer accumulated_time;
|
||||
StatRecord() :
|
||||
invocations(0),
|
||||
accumulated_time(elapsedTimer()) {}
|
||||
};
|
||||
private:
|
||||
StatRecord _stat_record;
|
||||
public:
|
||||
StatRecord* stat_record() { return &_stat_record; }
|
||||
|
||||
virtual void print_summary_info_on(outputStream* st);
|
||||
|
||||
// Performance Counter support
|
||||
virtual void update_counters() = 0;
|
||||
virtual CollectorCounters* counters() { return _gc_counters; }
|
||||
|
@ -314,7 +314,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size,
|
||||
for (uint try_count = 1, gclocker_stalled_count = 0; /* return or throw */; try_count += 1) {
|
||||
|
||||
// First allocation attempt is lock-free.
|
||||
Generation *young = _young_gen;
|
||||
DefNewGeneration *young = _young_gen;
|
||||
if (young->should_allocate(size, is_tlab)) {
|
||||
result = young->par_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
@ -379,7 +379,7 @@ HeapWord* SerialHeap::mem_allocate_work(size_t size,
|
||||
gc_count_before = total_collections();
|
||||
}
|
||||
|
||||
VM_GenCollectForAllocation op(size, is_tlab, gc_count_before);
|
||||
VM_SerialCollectForAllocation op(size, is_tlab, gc_count_before);
|
||||
VMThread::execute(&op);
|
||||
if (op.prologue_succeeded()) {
|
||||
result = op.result();
|
||||
@ -432,200 +432,61 @@ bool SerialHeap::must_clear_all_soft_refs() {
|
||||
_gc_cause == GCCause::_wb_full_gc;
|
||||
}
|
||||
|
||||
void SerialHeap::collect_generation(Generation* gen, bool full, size_t size,
|
||||
bool is_tlab, bool run_verification, bool clear_soft_refs) {
|
||||
FormatBuffer<> title("Collect gen: %s", gen->short_name());
|
||||
GCTraceTime(Trace, gc, phases) t1(title);
|
||||
TraceCollectorStats tcs(gen->counters());
|
||||
TraceMemoryManagerStats tmms(gen->gc_manager(), gc_cause(), heap()->is_young_gen(gen) ? "end of minor GC" : "end of major GC");
|
||||
bool SerialHeap::is_young_gc_safe() const {
|
||||
if (!_young_gen->to()->is_empty()) {
|
||||
return false;
|
||||
}
|
||||
return _old_gen->promotion_attempt_is_safe(_young_gen->used());
|
||||
}
|
||||
|
||||
gen->stat_record()->invocations++;
|
||||
gen->stat_record()->accumulated_time.start();
|
||||
bool SerialHeap::do_young_collection(bool clear_soft_refs) {
|
||||
if (!is_young_gc_safe()) {
|
||||
return false;
|
||||
}
|
||||
IsSTWGCActiveMark gc_active_mark;
|
||||
SvcGCMarker sgcm(SvcGCMarker::MINOR);
|
||||
GCIdMark gc_id_mark;
|
||||
GCTraceCPUTime tcpu(_young_gen->gc_tracer());
|
||||
GCTraceTime(Info, gc) t("Pause Young", nullptr, gc_cause(), true);
|
||||
TraceCollectorStats tcs(_young_gen->counters());
|
||||
TraceMemoryManagerStats tmms(_young_gen->gc_manager(), gc_cause(), "end of minor GC");
|
||||
print_heap_before_gc();
|
||||
const PreGenGCValues pre_gc_values = get_pre_gc_values();
|
||||
|
||||
// Must be done anew before each collection because
|
||||
// a previous collection will do mangling and will
|
||||
// change top of some spaces.
|
||||
record_gen_tops_before_GC();
|
||||
|
||||
log_trace(gc)("%s invoke=%d size=" SIZE_FORMAT, heap()->is_young_gen(gen) ? "Young" : "Old", gen->stat_record()->invocations, size * HeapWordSize);
|
||||
|
||||
if (run_verification && VerifyBeforeGC) {
|
||||
increment_total_collections(false);
|
||||
const bool should_verify = total_collections() >= VerifyGCStartAt;
|
||||
if (should_verify && VerifyBeforeGC) {
|
||||
prepare_for_verify();
|
||||
Universe::verify("Before GC");
|
||||
}
|
||||
gc_prologue(false);
|
||||
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::clear());
|
||||
|
||||
// Do collection work
|
||||
{
|
||||
save_marks(); // save marks for all gens
|
||||
save_marks();
|
||||
|
||||
gen->collect(full, clear_soft_refs, size, is_tlab);
|
||||
}
|
||||
bool result = _young_gen->collect(clear_soft_refs);
|
||||
|
||||
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers());
|
||||
|
||||
gen->stat_record()->accumulated_time.stop();
|
||||
update_gc_stats(_young_gen, false);
|
||||
|
||||
update_gc_stats(gen, full);
|
||||
|
||||
if (run_verification && VerifyAfterGC) {
|
||||
if (should_verify && VerifyAfterGC) {
|
||||
Universe::verify("After GC");
|
||||
}
|
||||
}
|
||||
|
||||
void SerialHeap::do_collection(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab,
|
||||
GenerationType max_generation) {
|
||||
ResourceMark rm;
|
||||
DEBUG_ONLY(Thread* my_thread = Thread::current();)
|
||||
_young_gen->compute_new_size();
|
||||
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint");
|
||||
assert(my_thread->is_VM_thread(), "only VM thread");
|
||||
assert(Heap_lock->is_locked(),
|
||||
"the requesting thread should have the Heap_lock");
|
||||
guarantee(!is_stw_gc_active(), "collection is not reentrant");
|
||||
print_heap_change(pre_gc_values);
|
||||
|
||||
if (GCLocker::check_active_before_gc()) {
|
||||
return; // GC is disabled (e.g. JNI GetXXXCritical operation)
|
||||
}
|
||||
// Track memory usage and detect low memory after GC finishes
|
||||
MemoryService::track_memory_usage();
|
||||
|
||||
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
|
||||
soft_ref_policy()->should_clear_all_soft_refs();
|
||||
gc_epilogue(false);
|
||||
|
||||
ClearedAllSoftRefs casr(do_clear_all_soft_refs, soft_ref_policy());
|
||||
print_heap_after_gc();
|
||||
|
||||
IsSTWGCActiveMark active_gc_mark;
|
||||
|
||||
bool complete = full && (max_generation == OldGen);
|
||||
bool old_collects_young = complete;
|
||||
bool do_young_collection = !old_collects_young && _young_gen->should_collect(full, size, is_tlab);
|
||||
|
||||
const PreGenGCValues pre_gc_values = get_pre_gc_values();
|
||||
|
||||
bool run_verification = total_collections() >= VerifyGCStartAt;
|
||||
bool prepared_for_verification = false;
|
||||
bool do_full_collection = false;
|
||||
|
||||
if (do_young_collection) {
|
||||
GCIdMark gc_id_mark;
|
||||
GCTraceCPUTime tcpu(((DefNewGeneration*)_young_gen)->gc_tracer());
|
||||
GCTraceTime(Info, gc) t("Pause Young", nullptr, gc_cause(), true);
|
||||
|
||||
print_heap_before_gc();
|
||||
|
||||
if (run_verification && VerifyBeforeGC) {
|
||||
prepare_for_verify();
|
||||
prepared_for_verification = true;
|
||||
}
|
||||
|
||||
gc_prologue(complete);
|
||||
increment_total_collections(complete);
|
||||
|
||||
collect_generation(_young_gen,
|
||||
full,
|
||||
size,
|
||||
is_tlab,
|
||||
run_verification,
|
||||
do_clear_all_soft_refs);
|
||||
|
||||
if (size > 0 && (!is_tlab || _young_gen->supports_tlab_allocation()) &&
|
||||
size * HeapWordSize <= _young_gen->unsafe_max_alloc_nogc()) {
|
||||
// Allocation request was met by young GC.
|
||||
size = 0;
|
||||
}
|
||||
|
||||
// Ask if young collection is enough. If so, do the final steps for young collection,
|
||||
// and fallthrough to the end.
|
||||
do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation);
|
||||
if (!do_full_collection) {
|
||||
// Adjust generation sizes.
|
||||
_young_gen->compute_new_size();
|
||||
|
||||
print_heap_change(pre_gc_values);
|
||||
|
||||
// Track memory usage and detect low memory after GC finishes
|
||||
MemoryService::track_memory_usage();
|
||||
|
||||
gc_epilogue(complete);
|
||||
}
|
||||
|
||||
print_heap_after_gc();
|
||||
|
||||
} else {
|
||||
// No young collection, ask if we need to perform Full collection.
|
||||
do_full_collection = should_do_full_collection(size, full, is_tlab, max_generation);
|
||||
}
|
||||
|
||||
if (do_full_collection) {
|
||||
GCIdMark gc_id_mark;
|
||||
GCTraceCPUTime tcpu(SerialFullGC::gc_tracer());
|
||||
GCTraceTime(Info, gc) t("Pause Full", nullptr, gc_cause(), true);
|
||||
|
||||
print_heap_before_gc();
|
||||
|
||||
if (!prepared_for_verification && run_verification && VerifyBeforeGC) {
|
||||
prepare_for_verify();
|
||||
}
|
||||
|
||||
if (!do_young_collection) {
|
||||
gc_prologue(complete);
|
||||
increment_total_collections(complete);
|
||||
}
|
||||
|
||||
// Accounting quirk: total full collections would be incremented when "complete"
|
||||
// is set, by calling increment_total_collections above. However, we also need to
|
||||
// account Full collections that had "complete" unset.
|
||||
if (!complete) {
|
||||
increment_total_full_collections();
|
||||
}
|
||||
|
||||
CodeCache::on_gc_marking_cycle_start();
|
||||
|
||||
ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
|
||||
false /* unregister_nmethods_during_purge */,
|
||||
false /* lock_nmethod_free_separately */);
|
||||
|
||||
collect_generation(_old_gen,
|
||||
full,
|
||||
size,
|
||||
is_tlab,
|
||||
run_verification,
|
||||
do_clear_all_soft_refs);
|
||||
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
CodeCache::arm_all_nmethods();
|
||||
|
||||
// Adjust generation sizes.
|
||||
_old_gen->compute_new_size();
|
||||
_young_gen->compute_new_size();
|
||||
|
||||
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
|
||||
ClassLoaderDataGraph::purge(/*at_safepoint*/true);
|
||||
DEBUG_ONLY(MetaspaceUtils::verify();)
|
||||
|
||||
// Need to clear claim bits for the next mark.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
// Resize the metaspace capacity after full collections
|
||||
MetaspaceGC::compute_new_size();
|
||||
|
||||
print_heap_change(pre_gc_values);
|
||||
|
||||
// Track memory usage and detect low memory after GC finishes
|
||||
MemoryService::track_memory_usage();
|
||||
|
||||
// Need to tell the epilogue code we are done with Full GC, regardless what was
|
||||
// the initial value for "complete" flag.
|
||||
gc_epilogue(true);
|
||||
|
||||
print_heap_after_gc();
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialHeap::should_do_full_collection(size_t size, bool full, bool is_tlab,
|
||||
SerialHeap::GenerationType max_gen) const {
|
||||
return max_gen == OldGen && _old_gen->should_collect(full, size, is_tlab);
|
||||
return result;
|
||||
}
|
||||
|
||||
void SerialHeap::register_nmethod(nmethod* nm) {
|
||||
@ -649,10 +510,11 @@ void SerialHeap::prune_unlinked_nmethods() {
|
||||
}
|
||||
|
||||
HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
|
||||
GCCauseSetter x(this, GCCause::_allocation_failure);
|
||||
assert(size != 0, "precondition");
|
||||
|
||||
HeapWord* result = nullptr;
|
||||
|
||||
assert(size != 0, "Precondition violated");
|
||||
GCLocker::check_active_before_gc();
|
||||
if (GCLocker::is_active_and_needs_gc()) {
|
||||
// GC locker is active; instead of a collection we will attempt
|
||||
// to expand the heap, if there's room for expansion.
|
||||
@ -660,30 +522,14 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
}
|
||||
return result; // Could be null if we are out of space.
|
||||
} else if (!incremental_collection_will_fail(false /* don't consult_young */)) {
|
||||
// Do an incremental collection.
|
||||
do_collection(false, // full
|
||||
false, // clear_all_soft_refs
|
||||
size, // size
|
||||
is_tlab, // is_tlab
|
||||
SerialHeap::OldGen); // max_generation
|
||||
} else {
|
||||
log_trace(gc)(" :: Trying full because partial may fail :: ");
|
||||
// Try a full collection; see delta for bug id 6266275
|
||||
// for the original code and why this has been simplified
|
||||
// with from-space allocation criteria modified and
|
||||
// such allocation moved out of the safepoint path.
|
||||
do_collection(true, // full
|
||||
false, // clear_all_soft_refs
|
||||
size, // size
|
||||
is_tlab, // is_tlab
|
||||
SerialHeap::OldGen); // max_generation
|
||||
}
|
||||
|
||||
result = attempt_allocation(size, is_tlab, false /*first_only*/);
|
||||
// If young-gen can handle this allocation, attempt young-gc firstly.
|
||||
bool should_run_young_gc = _young_gen->should_allocate(size, is_tlab);
|
||||
collect_at_safepoint(!should_run_young_gc);
|
||||
|
||||
result = attempt_allocation(size, is_tlab, false /*first_only*/);
|
||||
if (result != nullptr) {
|
||||
assert(is_in_reserved(result), "result not in heap");
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -700,17 +546,17 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) {
|
||||
// attempt fails, an OOM exception will be thrown.
|
||||
{
|
||||
UIntFlagSetting flag_change(MarkSweepAlwaysCompactCount, 1); // Make sure the heap is fully compacted
|
||||
|
||||
do_collection(true, // full
|
||||
true, // clear_all_soft_refs
|
||||
size, // size
|
||||
is_tlab, // is_tlab
|
||||
SerialHeap::OldGen); // max_generation
|
||||
const bool clear_all_soft_refs = true;
|
||||
do_full_collection_no_gc_locker(clear_all_soft_refs);
|
||||
}
|
||||
|
||||
result = attempt_allocation(size, is_tlab, false /* first_only */);
|
||||
if (result != nullptr) {
|
||||
assert(is_in_reserved(result), "result not in heap");
|
||||
return result;
|
||||
}
|
||||
// The previous full-gc can shrink the heap, so re-expand it.
|
||||
result = expand_heap_and_allocate(size, is_tlab);
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -786,6 +632,28 @@ void SerialHeap::scan_evacuated_objs(YoungGenScanClosure* young_cl,
|
||||
guarantee(young_gen()->promo_failure_scan_is_complete(), "Failed to finish scan");
|
||||
}
|
||||
|
||||
void SerialHeap::try_collect_at_safepoint(bool full) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "precondition");
|
||||
if (GCLocker::check_active_before_gc()) {
|
||||
return;
|
||||
}
|
||||
collect_at_safepoint(full);
|
||||
}
|
||||
|
||||
void SerialHeap::collect_at_safepoint(bool full) {
|
||||
assert(!GCLocker::is_active(), "precondition");
|
||||
bool clear_soft_refs = must_clear_all_soft_refs();
|
||||
|
||||
if (!full) {
|
||||
bool success = do_young_collection(clear_soft_refs);
|
||||
if (success) {
|
||||
return;
|
||||
}
|
||||
// Upgrade to Full-GC if young-gc fails
|
||||
}
|
||||
do_full_collection_no_gc_locker(clear_soft_refs);
|
||||
}
|
||||
|
||||
// public collection interfaces
|
||||
void SerialHeap::collect(GCCause::Cause cause) {
|
||||
// The caller doesn't have the Heap_lock
|
||||
@ -809,13 +677,11 @@ void SerialHeap::collect(GCCause::Cause cause) {
|
||||
|| (cause == GCCause::_gc_locker)
|
||||
DEBUG_ONLY(|| (cause == GCCause::_scavenge_alot));
|
||||
|
||||
const GenerationType max_generation = should_run_young_gc
|
||||
? YoungGen
|
||||
: OldGen;
|
||||
|
||||
while (true) {
|
||||
VM_GenCollectFull op(gc_count_before, full_gc_count_before,
|
||||
cause, max_generation);
|
||||
VM_SerialGCCollect op(!should_run_young_gc,
|
||||
gc_count_before,
|
||||
full_gc_count_before,
|
||||
cause);
|
||||
VMThread::execute(&op);
|
||||
|
||||
if (!GCCause::is_explicit_full_gc(cause)) {
|
||||
@ -838,27 +704,83 @@ void SerialHeap::collect(GCCause::Cause cause) {
|
||||
}
|
||||
|
||||
void SerialHeap::do_full_collection(bool clear_all_soft_refs) {
|
||||
do_full_collection(clear_all_soft_refs, OldGen);
|
||||
if (GCLocker::check_active_before_gc()) {
|
||||
return;
|
||||
}
|
||||
do_full_collection_no_gc_locker(clear_all_soft_refs);
|
||||
}
|
||||
|
||||
void SerialHeap::do_full_collection(bool clear_all_soft_refs,
|
||||
GenerationType last_generation) {
|
||||
do_collection(true, // full
|
||||
clear_all_soft_refs, // clear_all_soft_refs
|
||||
0, // size
|
||||
false, // is_tlab
|
||||
last_generation); // last_generation
|
||||
// Hack XXX FIX ME !!!
|
||||
// A scavenge may not have been attempted, or may have
|
||||
// been attempted and failed, because the old gen was too full
|
||||
if (gc_cause() == GCCause::_gc_locker && incremental_collection_failed()) {
|
||||
log_debug(gc, jni)("GC locker: Trying a full collection because scavenge failed");
|
||||
// This time allow the old gen to be collected as well
|
||||
do_collection(true, // full
|
||||
clear_all_soft_refs, // clear_all_soft_refs
|
||||
0, // size
|
||||
false, // is_tlab
|
||||
OldGen); // last_generation
|
||||
void SerialHeap::do_full_collection_no_gc_locker(bool clear_all_soft_refs) {
|
||||
IsSTWGCActiveMark gc_active_mark;
|
||||
SvcGCMarker sgcm(SvcGCMarker::FULL);
|
||||
GCIdMark gc_id_mark;
|
||||
GCTraceCPUTime tcpu(SerialFullGC::gc_tracer());
|
||||
GCTraceTime(Info, gc) t("Pause Full", nullptr, gc_cause(), true);
|
||||
TraceCollectorStats tcs(_old_gen->counters());
|
||||
TraceMemoryManagerStats tmms(_old_gen->gc_manager(), gc_cause(), "end of major GC");
|
||||
const PreGenGCValues pre_gc_values = get_pre_gc_values();
|
||||
print_heap_before_gc();
|
||||
|
||||
increment_total_collections(true);
|
||||
const bool should_verify = total_collections() >= VerifyGCStartAt;
|
||||
if (should_verify && VerifyBeforeGC) {
|
||||
prepare_for_verify();
|
||||
Universe::verify("Before GC");
|
||||
}
|
||||
|
||||
gc_prologue(true);
|
||||
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::clear());
|
||||
CodeCache::on_gc_marking_cycle_start();
|
||||
ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */,
|
||||
false /* unregister_nmethods_during_purge */,
|
||||
false /* lock_nmethod_free_separately */);
|
||||
|
||||
STWGCTimer* gc_timer = SerialFullGC::gc_timer();
|
||||
gc_timer->register_gc_start();
|
||||
|
||||
SerialOldTracer* gc_tracer = SerialFullGC::gc_tracer();
|
||||
gc_tracer->report_gc_start(gc_cause(), gc_timer->gc_start());
|
||||
|
||||
pre_full_gc_dump(gc_timer);
|
||||
|
||||
SerialFullGC::invoke_at_safepoint(clear_all_soft_refs);
|
||||
|
||||
post_full_gc_dump(gc_timer);
|
||||
|
||||
gc_timer->register_gc_end();
|
||||
|
||||
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
|
||||
CodeCache::on_gc_marking_cycle_finish();
|
||||
CodeCache::arm_all_nmethods();
|
||||
COMPILER2_OR_JVMCI_PRESENT(DerivedPointerTable::update_pointers());
|
||||
|
||||
// Adjust generation sizes.
|
||||
_old_gen->compute_new_size();
|
||||
_young_gen->compute_new_size();
|
||||
|
||||
// Delete metaspaces for unloaded class loaders and clean up loader_data graph
|
||||
ClassLoaderDataGraph::purge(/*at_safepoint*/true);
|
||||
DEBUG_ONLY(MetaspaceUtils::verify();)
|
||||
|
||||
// Need to clear claim bits for the next mark.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
// Resize the metaspace capacity after full collections
|
||||
MetaspaceGC::compute_new_size();
|
||||
|
||||
print_heap_change(pre_gc_values);
|
||||
|
||||
// Track memory usage and detect low memory after GC finishes
|
||||
MemoryService::track_memory_usage();
|
||||
|
||||
// Need to tell the epilogue code we are done with Full GC, regardless what was
|
||||
// the initial value for "complete" flag.
|
||||
gc_epilogue(true);
|
||||
|
||||
print_heap_after_gc();
|
||||
|
||||
if (should_verify && VerifyAfterGC) {
|
||||
Universe::verify("After GC");
|
||||
}
|
||||
}
|
||||
|
||||
@ -982,11 +904,7 @@ bool SerialHeap::print_location(outputStream* st, void* addr) const {
|
||||
}
|
||||
|
||||
void SerialHeap::print_tracing_info() const {
|
||||
if (log_is_enabled(Debug, gc, heap, exit)) {
|
||||
LogStreamHandle(Debug, gc, heap, exit) lsh;
|
||||
_young_gen->print_summary_info_on(&lsh);
|
||||
_old_gen->print_summary_info_on(&lsh);
|
||||
}
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
void SerialHeap::print_heap_change(const PreGenGCValues& pre_gc_values) const {
|
||||
|
@ -67,8 +67,6 @@ class SerialHeap : public CollectedHeap {
|
||||
friend class DefNewGeneration;
|
||||
friend class TenuredGeneration;
|
||||
friend class SerialFullGC;
|
||||
friend class VM_GenCollectForAllocation;
|
||||
friend class VM_GenCollectFull;
|
||||
friend class VM_GC_HeapInspection;
|
||||
friend class VM_HeapDumper;
|
||||
friend class HeapInspection;
|
||||
@ -87,7 +85,7 @@ private:
|
||||
TenuredGeneration* _old_gen;
|
||||
HeapWord* _young_gen_saved_top;
|
||||
HeapWord* _old_gen_saved_top;
|
||||
private:
|
||||
|
||||
// The singleton CardTable Remembered Set.
|
||||
CardTableRS* _rem_set;
|
||||
|
||||
@ -98,16 +96,13 @@ private:
|
||||
// condition that caused that incremental collection to fail.
|
||||
bool _incremental_collection_failed;
|
||||
|
||||
// Collects the given generation.
|
||||
void collect_generation(Generation* gen, bool full, size_t size, bool is_tlab,
|
||||
bool run_verification, bool clear_soft_refs);
|
||||
bool do_young_collection(bool clear_soft_refs);
|
||||
|
||||
// Reserve aligned space for the heap as needed by the contained generations.
|
||||
ReservedHeapSpace allocate(size_t alignment);
|
||||
|
||||
PreGenGCValues get_pre_gc_values() const;
|
||||
|
||||
private:
|
||||
GCMemoryManager* _young_manager;
|
||||
GCMemoryManager* _old_manager;
|
||||
|
||||
@ -116,29 +111,17 @@ private:
|
||||
bool is_tlab,
|
||||
bool first_only);
|
||||
|
||||
// Helper function for two callbacks below.
|
||||
// Considers collection of the first max_level+1 generations.
|
||||
void do_collection(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab,
|
||||
GenerationType max_generation);
|
||||
|
||||
// Callback from VM_GenCollectForAllocation operation.
|
||||
// This function does everything necessary/possible to satisfy an
|
||||
// allocation request that failed in the youngest generation that should
|
||||
// have handled it (including collection, expansion, etc.)
|
||||
HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab);
|
||||
|
||||
// Callback from VM_GenCollectFull operation.
|
||||
// Perform a full collection of the first max_level+1 generations.
|
||||
void do_full_collection(bool clear_all_soft_refs) override;
|
||||
void do_full_collection(bool clear_all_soft_refs, GenerationType max_generation);
|
||||
void do_full_collection_no_gc_locker(bool clear_all_soft_refs);
|
||||
|
||||
void collect_at_safepoint(bool full);
|
||||
|
||||
// Does the "cause" of GC indicate that
|
||||
// we absolutely __must__ clear soft refs?
|
||||
bool must_clear_all_soft_refs();
|
||||
|
||||
bool is_young_gc_safe() const;
|
||||
|
||||
public:
|
||||
// Returns JNI_OK on success
|
||||
jint initialize() override;
|
||||
@ -159,6 +142,15 @@ public:
|
||||
|
||||
HeapWord* mem_allocate(size_t size, bool* gc_overhead_limit_was_exceeded) override;
|
||||
|
||||
// Callback from VM_SerialCollectForAllocation operation.
|
||||
// This function does everything necessary/possible to satisfy an
|
||||
// allocation request that failed in the youngest generation that should
|
||||
// have handled it (including collection, expansion, etc.)
|
||||
HeapWord* satisfy_failed_allocation(size_t size, bool is_tlab);
|
||||
|
||||
// Callback from VM_SerialGCCollect.
|
||||
void try_collect_at_safepoint(bool full);
|
||||
|
||||
// Perform a full collection of the heap; intended for use in implementing
|
||||
// "System.gc". This implies as full a collection as the CollectedHeap
|
||||
// supports. Caller does not hold the Heap_lock on entry.
|
||||
@ -305,10 +297,6 @@ private:
|
||||
// Save the tops of the spaces in all generations
|
||||
void record_gen_tops_before_GC() PRODUCT_RETURN;
|
||||
|
||||
// Return true if we need to perform full collection.
|
||||
bool should_do_full_collection(size_t size, bool full,
|
||||
bool is_tlab, GenerationType max_gen) const;
|
||||
|
||||
private:
|
||||
MemoryPool* _eden_pool;
|
||||
MemoryPool* _survivor_pool;
|
||||
|
@ -26,9 +26,7 @@
|
||||
#include "gc/serial/serialVMOperations.hpp"
|
||||
#include "gc/shared/gcLocker.hpp"
|
||||
|
||||
void VM_GenCollectForAllocation::doit() {
|
||||
SvcGCMarker sgcm(SvcGCMarker::MINOR);
|
||||
|
||||
void VM_SerialCollectForAllocation::doit() {
|
||||
SerialHeap* gch = SerialHeap::heap();
|
||||
GCCauseSetter gccs(gch, _gc_cause);
|
||||
_result = gch->satisfy_failed_allocation(_word_size, _tlab);
|
||||
@ -39,10 +37,8 @@ void VM_GenCollectForAllocation::doit() {
|
||||
}
|
||||
}
|
||||
|
||||
void VM_GenCollectFull::doit() {
|
||||
SvcGCMarker sgcm(SvcGCMarker::FULL);
|
||||
|
||||
void VM_SerialGCCollect::doit() {
|
||||
SerialHeap* gch = SerialHeap::heap();
|
||||
GCCauseSetter gccs(gch, _gc_cause);
|
||||
gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_generation);
|
||||
gch->try_collect_at_safepoint(_full);
|
||||
}
|
||||
|
@ -28,37 +28,32 @@
|
||||
#include "gc/serial/serialHeap.hpp"
|
||||
#include "gc/shared/gcVMOperations.hpp"
|
||||
|
||||
class VM_GenCollectForAllocation : public VM_CollectForAllocation {
|
||||
class VM_SerialCollectForAllocation : public VM_CollectForAllocation {
|
||||
private:
|
||||
bool _tlab; // alloc is of a tlab.
|
||||
public:
|
||||
VM_GenCollectForAllocation(size_t word_size,
|
||||
bool tlab,
|
||||
uint gc_count_before)
|
||||
VM_SerialCollectForAllocation(size_t word_size,
|
||||
bool tlab,
|
||||
uint gc_count_before)
|
||||
: VM_CollectForAllocation(word_size, gc_count_before, GCCause::_allocation_failure),
|
||||
_tlab(tlab) {
|
||||
assert(word_size != 0, "An allocation should always be requested with this operation.");
|
||||
}
|
||||
~VM_GenCollectForAllocation() {}
|
||||
virtual VMOp_Type type() const { return VMOp_GenCollectForAllocation; }
|
||||
virtual VMOp_Type type() const { return VMOp_SerialCollectForAllocation; }
|
||||
virtual void doit();
|
||||
};
|
||||
|
||||
// VM operation to invoke a collection of the heap as a
|
||||
// SerialHeap heap.
|
||||
class VM_GenCollectFull: public VM_GC_Operation {
|
||||
private:
|
||||
SerialHeap::GenerationType _max_generation;
|
||||
class VM_SerialGCCollect: public VM_GC_Operation {
|
||||
public:
|
||||
VM_GenCollectFull(uint gc_count_before,
|
||||
uint full_gc_count_before,
|
||||
GCCause::Cause gc_cause,
|
||||
SerialHeap::GenerationType max_generation)
|
||||
: VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before,
|
||||
max_generation != SerialHeap::YoungGen /* full */),
|
||||
_max_generation(max_generation) { }
|
||||
~VM_GenCollectFull() {}
|
||||
virtual VMOp_Type type() const { return VMOp_GenCollectFull; }
|
||||
VM_SerialGCCollect(bool full,
|
||||
uint gc_count_before,
|
||||
uint full_gc_count_before,
|
||||
GCCause::Cause gc_cause)
|
||||
: VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, full) {}
|
||||
|
||||
virtual VMOp_Type type() const { return VMOp_SerialGCCollect; }
|
||||
virtual void doit();
|
||||
};
|
||||
|
||||
|
@ -453,29 +453,6 @@ oop TenuredGeneration::promote(oop obj, size_t obj_size) {
|
||||
return new_obj;
|
||||
}
|
||||
|
||||
void TenuredGeneration::collect(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab) {
|
||||
SerialHeap* gch = SerialHeap::heap();
|
||||
|
||||
STWGCTimer* gc_timer = SerialFullGC::gc_timer();
|
||||
gc_timer->register_gc_start();
|
||||
|
||||
SerialOldTracer* gc_tracer = SerialFullGC::gc_tracer();
|
||||
gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start());
|
||||
|
||||
gch->pre_full_gc_dump(gc_timer);
|
||||
|
||||
SerialFullGC::invoke_at_safepoint(clear_all_soft_refs);
|
||||
|
||||
gch->post_full_gc_dump(gc_timer);
|
||||
|
||||
gc_timer->register_gc_end();
|
||||
|
||||
gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions());
|
||||
}
|
||||
|
||||
HeapWord*
|
||||
TenuredGeneration::expand_and_allocate(size_t word_size, bool is_tlab) {
|
||||
assert(!is_tlab, "TenuredGeneration does not support TLAB allocation");
|
||||
|
@ -135,11 +135,6 @@ public:
|
||||
virtual inline HeapWord* allocate(size_t word_size, bool is_tlab);
|
||||
virtual inline HeapWord* par_allocate(size_t word_size, bool is_tlab);
|
||||
|
||||
virtual void collect(bool full,
|
||||
bool clear_all_soft_refs,
|
||||
size_t size,
|
||||
bool is_tlab);
|
||||
|
||||
HeapWord* expand_and_allocate(size_t size, bool is_tlab);
|
||||
|
||||
void gc_prologue();
|
||||
@ -149,6 +144,15 @@ public:
|
||||
size_t word_size,
|
||||
bool is_tlab);
|
||||
|
||||
bool should_allocate(size_t word_size, bool is_tlab) {
|
||||
bool result = false;
|
||||
size_t overflow_limit = (size_t)1 << (BitsPerSize_t - LogHeapWordSize);
|
||||
if (!is_tlab || supports_tlab_allocation()) {
|
||||
result = (word_size > 0) && (word_size < overflow_limit);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Performance Counter support
|
||||
void update_counters();
|
||||
|
||||
|
@ -36,10 +36,6 @@
|
||||
static_field) \
|
||||
nonstatic_field(Generation, _reserved, MemRegion) \
|
||||
nonstatic_field(Generation, _virtual_space, VirtualSpace) \
|
||||
nonstatic_field(Generation, _stat_record, Generation::StatRecord) \
|
||||
\
|
||||
nonstatic_field(Generation::StatRecord, invocations, int) \
|
||||
nonstatic_field(Generation::StatRecord, accumulated_time, elapsedTimer) \
|
||||
\
|
||||
nonstatic_field(TenuredGeneration, _rs, CardTableRS*) \
|
||||
nonstatic_field(TenuredGeneration, _bts, SerialBlockOffsetTable*) \
|
||||
@ -67,7 +63,6 @@
|
||||
declare_toplevel_type, \
|
||||
declare_integer_type) \
|
||||
declare_toplevel_type(Generation) \
|
||||
declare_toplevel_type(Generation::StatRecord) \
|
||||
declare_type(SerialHeap, CollectedHeap) \
|
||||
declare_type(TenuredGeneration, Generation) \
|
||||
\
|
||||
|
@ -41,10 +41,10 @@
|
||||
// VM_GC_Operation
|
||||
// VM_GC_HeapInspection
|
||||
// VM_PopulateDynamicDumpSharedSpace
|
||||
// VM_GenCollectFull
|
||||
// VM_SerialGCCollect
|
||||
// VM_ParallelGCSystemGC
|
||||
// VM_CollectForAllocation
|
||||
// VM_GenCollectForAllocation
|
||||
// VM_SerialCollectForAllocation
|
||||
// VM_ParallelGCFailedAllocation
|
||||
// VM_Verify
|
||||
// VM_PopulateDumpSharedSpace
|
||||
@ -63,13 +63,13 @@
|
||||
// is specified; and also the attach "inspectheap" operation
|
||||
//
|
||||
// VM_CollectForAllocation
|
||||
// VM_GenCollectForAllocation
|
||||
// VM_SerialCollectForAllocation
|
||||
// VM_ParallelGCFailedAllocation
|
||||
// - this operation is invoked when allocation is failed;
|
||||
// operation performs garbage collection and tries to
|
||||
// allocate afterwards;
|
||||
//
|
||||
// VM_GenCollectFull
|
||||
// VM_SerialGCCollect
|
||||
// VM_ParallelGCSystemGC
|
||||
// - these operations perform full collection of heaps of
|
||||
// different kind
|
||||
|
@ -50,8 +50,8 @@
|
||||
template(CollectForMetadataAllocation) \
|
||||
template(CollectForCodeCacheAllocation) \
|
||||
template(GC_HeapInspection) \
|
||||
template(GenCollectFull) \
|
||||
template(GenCollectForAllocation) \
|
||||
template(SerialCollectForAllocation) \
|
||||
template(SerialGCCollect) \
|
||||
template(ParallelGCFailedAllocation) \
|
||||
template(ParallelGCSystemGC) \
|
||||
template(G1CollectForAllocation) \
|
||||
|
@ -50,9 +50,6 @@ public abstract class Generation extends VMObject {
|
||||
private static long reservedFieldOffset;
|
||||
private static long virtualSpaceFieldOffset;
|
||||
protected static final int K = 1024;
|
||||
// Fields for class StatRecord
|
||||
private static Field statRecordField;
|
||||
private static CIntegerField invocationField;
|
||||
|
||||
static {
|
||||
VM.registerVMInitializedObserver(new Observer() {
|
||||
@ -67,20 +64,12 @@ public abstract class Generation extends VMObject {
|
||||
|
||||
reservedFieldOffset = type.getField("_reserved").getOffset();
|
||||
virtualSpaceFieldOffset = type.getField("_virtual_space").getOffset();
|
||||
// StatRecord
|
||||
statRecordField = type.getField("_stat_record");
|
||||
type = db.lookupType("Generation::StatRecord");
|
||||
invocationField = type.getCIntegerField("invocations");
|
||||
}
|
||||
|
||||
public Generation(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public int invocations() {
|
||||
return getStatRecord().getInvocations();
|
||||
}
|
||||
|
||||
/** The maximum number of object bytes the generation can currently
|
||||
hold. */
|
||||
public abstract long capacity();
|
||||
@ -123,19 +112,4 @@ public abstract class Generation extends VMObject {
|
||||
|
||||
public void print() { printOn(System.out); }
|
||||
public abstract void printOn(PrintStream tty);
|
||||
|
||||
public static class StatRecord extends VMObject {
|
||||
public StatRecord(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
|
||||
public int getInvocations() {
|
||||
return (int) invocationField.getValue(addr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private StatRecord getStatRecord() {
|
||||
return VMObjectFactory.newObject(StatRecord.class, addr.addOffsetTo(statRecordField.getOffset()));
|
||||
}
|
||||
}
|
||||
|
@ -95,11 +95,11 @@ public class SerialHeap extends CollectedHeap {
|
||||
public void printOn(PrintStream tty) {
|
||||
tty.println("SerialHeap:");
|
||||
|
||||
tty.println("Young Generation - Invocations: " + youngGen().invocations());
|
||||
tty.println("Young Generation: ");
|
||||
youngGen().printOn(tty);
|
||||
tty.println();
|
||||
|
||||
tty.println("Old Generation - Invocations: " + oldGen().invocations());
|
||||
tty.println("Old Generation: ");
|
||||
oldGen().printOn(tty);
|
||||
tty.println();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user