--- old/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-10-18 18:01:51.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-10-18 18:01:51.000000000 -0400 @@ -644,7 +644,7 @@ curr_region->set_closed_archive(); } _hr_printer.alloc(curr_region); - _archive_set.add(curr_region); + archive_set_add(curr_region); HeapWord* top; HeapRegion* next_region; if (curr_region != last_region) { @@ -1606,7 +1606,6 @@ os::enable_vtime(); // Necessary to satisfy locking discipline assertions. - MutexLocker x(Heap_lock); // While there are no constraints in the GC code that HeapWordSize @@ -1833,6 +1832,9 @@ } void G1CollectedHeap::post_initialize() { + // Necessary to satisfy locking discipline assertions. + MutexLockerEx x(Heap_lock); + CollectedHeap::post_initialize(); ref_processing_init(); } @@ -2899,9 +2901,7 @@ active_workers = workers()->update_active_workers(active_workers); log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers()); - G1MonitoringScope ms(g1mm(), - false /* full_gc */, - collector_state()->yc_type() == Mixed /* all_memory_pools_affected */); + G1MonitoringScope ms(g1mm(), false /* full_gc */, collector_state()->yc_type() == Mixed /* mixed_gc */); G1HeapTransition heap_transition(this); size_t heap_used_bytes_before_gc = used(); --- old/src/hotspot/share/gc/g1/g1CollectedHeap.hpp 2018-10-18 18:01:53.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.hpp 2018-10-18 18:01:53.000000000 -0400 @@ -352,7 +352,7 @@ assert(Thread::current()->is_VM_thread(), "current thread is not VM thread"); \ } while (0) - // The young region list. + // The young region lists. G1EdenRegions _eden; G1SurvivorRegions _survivor; @@ -1041,7 +1041,7 @@ inline void archive_set_add(HeapRegion* hr); size_t non_young_capacity_bytes() { - return (old_regions_count() + _archive_set.length() + humongous_regions_count()) * HeapRegion::GrainBytes; + return (old_regions_count() + archive_regions_count() + humongous_regions_count()) * HeapRegion::GrainBytes; } // Determine whether the given region is one that we are using as an @@ -1216,19 +1216,18 @@ virtual jlong millis_since_last_gc(); - // Convenience function to be used in situations where the heap type can be // asserted to be this type. static G1CollectedHeap* heap(); void set_region_short_lived_locked(HeapRegion* hr); - // add appropriate methods for any other surv rate groups + // add appropriate methods for any other survivor rate groups const G1SurvivorRegions* survivor() const { return &_survivor; } uint eden_regions_count() const { return _eden.length(); } uint survivor_regions_count() const { return _survivor.length(); } - uint young_regions_count() const { return _eden.length() + _survivor.length(); } + uint young_regions_count() const { return eden_regions_count() + survivor_regions_count(); } uint old_regions_count() const { return _old_set.length(); } uint archive_regions_count() const { return _archive_set.length(); } uint humongous_regions_count() const { return _humongous_set.length(); } --- old/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2018-10-18 18:01:55.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2018-10-18 18:01:54.000000000 -0400 @@ -929,6 +929,8 @@ _gc_tracer_cm->report_gc_start(GCCause::_no_gc /* first parameter is not used */, _gc_timer_cm->gc_start()); _g1h->trace_heap_before_gc(_gc_tracer_cm); + // Record start, but take no time + TraceConcMemoryManagerStats tms(TraceConcMemoryManagerStats::CycleStart, _g1h->gc_cause()); } void G1ConcurrentMark::concurrent_cycle_end() { @@ -944,6 +946,8 @@ _gc_timer_cm->register_gc_end(); _gc_tracer_cm->report_gc_end(_gc_timer_cm->gc_end(), _gc_timer_cm->time_partitions()); + // Record end, but take no time + TraceConcMemoryManagerStats tms(TraceConcMemoryManagerStats::CycleEnd, _g1h->gc_cause()); } void G1ConcurrentMark::mark_from_roots() { @@ -1121,6 +1125,8 @@ return; } + TraceConcMemoryManagerStats tms(TraceConcMemoryManagerStats::Remark, _g1h->gc_cause()); + G1Policy* g1p = _g1h->g1_policy(); g1p->record_concurrent_mark_remark_start(); @@ -1337,6 +1343,8 @@ return; } + TraceConcMemoryManagerStats tms(TraceConcMemoryManagerStats::Cleanup, _g1h->gc_cause()); + G1Policy* g1p = _g1h->g1_policy(); g1p->record_concurrent_mark_cleanup_start(); --- old/src/hotspot/share/gc/g1/g1FullGCScope.cpp 2018-10-18 18:01:56.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1FullGCScope.cpp 2018-10-18 18:01:56.000000000 -0400 @@ -36,7 +36,7 @@ _active(), _cpu_time(), _soft_refs(clear_soft, _g1h->soft_ref_policy()), - _monitoring_scope(monitoring_support, true /* full_gc */, true /* all_memory_pools_affected */), + _monitoring_scope(monitoring_support, true /* full_gc */, false /* mixed_gc */), _heap_transition(_g1h) { _timer.register_gc_start(); _tracer.report_gc_start(_g1h->gc_cause(), _timer.gc_start()); --- old/src/hotspot/share/gc/g1/g1MemoryPool.cpp 2018-10-18 18:01:57.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1MemoryPool.cpp 2018-10-18 18:01:57.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, 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 @@ -62,13 +62,35 @@ return _g1mm->survivor_space_memory_usage(initial_size(), max_size()); } -G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h, size_t initial_size, size_t max_size) : +G1OldPool::G1OldPool(G1CollectedHeap* g1h, size_t initial_size, size_t max_size) : G1MemoryPoolSuper(g1h, - "G1 Old Gen", + g1h->g1mm()->use_legacy_monitoring() ? "G1 Old Gen" : "G1 Old Space", initial_size, max_size, true /* support_usage_threshold */) { } -MemoryUsage G1OldGenPool::get_memory_usage() { - return _g1mm->old_gen_memory_usage(initial_size(), max_size()); +MemoryUsage G1OldPool::get_memory_usage() { + return _g1mm->old_space_memory_usage(initial_size(), max_size()); +} + +G1ArchivePool::G1ArchivePool(G1CollectedHeap* g1h, size_t initial_size) : + G1MemoryPoolSuper(g1h, + "G1 Archive Space", + initial_size, + MemoryUsage::undefined_size(), + false /* support_usage_threshold */) { } + +MemoryUsage G1ArchivePool::get_memory_usage() { + return _g1mm->archive_space_memory_usage(initial_size(), max_size()); +} + +G1HumongousPool::G1HumongousPool(G1CollectedHeap* g1h, size_t initial_size) : + G1MemoryPoolSuper(g1h, + "G1 Humongous Space", + initial_size, + MemoryUsage::undefined_size(), + true /* support_usage_threshold */) { } + +MemoryUsage G1HumongousPool::get_memory_usage() { + return _g1mm->humongous_space_memory_usage(initial_size(), max_size()); } --- old/src/hotspot/share/gc/g1/g1MemoryPool.hpp 2018-10-18 18:01:58.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1MemoryPool.hpp 2018-10-18 18:01:58.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2018, 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 @@ -29,28 +29,28 @@ #include "services/memoryPool.hpp" #include "services/memoryUsage.hpp" -// This file contains the three classes that represent the memory -// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and -// G1OldGenPool. In G1, unlike our other GCs, we do not have a -// physical space for each of those spaces. Instead, we allocate -// regions for all three spaces out of a single pool of regions (that -// pool basically covers the entire heap). As a result, the eden, -// survivor, and old gen are considered logical spaces in G1, as each -// is a set of non-contiguous regions. This is also reflected in the -// way we map them to memory pools here. The easiest way to have done -// this would have been to map the entire G1 heap to a single memory -// pool. However, it's helpful to show how large the eden and survivor -// get, as this does affect the performance and behavior of G1. Which -// is why we introduce the three memory pools implemented here. +// This file contains definitions for two memory pool models for the G1 heap +// spaces. Which to use is determined by the G1UseLegacyMonitoring switch. If +// true, we use a model that defines three pools, G1EdenPool, G1SurvivorPool +// and G1OldPool. If false (the default), we use a more accurate model +// that defines two additional pools, G1HumongousPool and G1ArchivePool. // -// See comments in g1MonitoringSupport.hpp for additional details -// on this model. +// In G1, unlike our other GCs, we do not have a contiguous virtual address +// space for each pool. The pools are logical spaces in G1, and each pool +// consists of a non-contiguous region set allocated out of a single region +// pool which covers the entire heap. This is also reflected in the way we +// map them to memory pools here. The easiest way to have done this would +// have been to map the entire G1 heap to a single memory pool. However, it +// is helpful to show how large each space gets, as their sizes affect G1's +// performance and behavior. // +// See comments in g1MonitoringSupport.hpp for additional details on this +// model. class G1CollectedHeap; -// This class is shared by the three G1 memory pool classes -// (G1EdenPool, G1SurvivorPool, G1OldGenPool). +// This class is shared by all G1 memory pool classes: G1EdenPool, +// G1SurvivorPool, G1OldPool, G1HumongousPool, and G1ArchivePool class G1MemoryPoolSuper : public CollectedMemoryPool { protected: G1MonitoringSupport* _g1mm; @@ -63,33 +63,54 @@ bool support_usage_threshold); }; -// Memory pool that represents the G1 eden. +// In legacy mode, G1EdenPool, G1SurvivorPool, and G1OldPool represent +// the G1 memory pools, and G1OldPool includes regions occupied by +// humongous and archive objects. + +// Memory pool that represents the G1 eden space class G1EdenPool : public G1MemoryPoolSuper { public: G1EdenPool(G1CollectedHeap* g1h, size_t initial_size); - size_t used_in_bytes() { return _g1mm->eden_space_used(); } - MemoryUsage get_memory_usage(); }; -// Memory pool that represents the G1 survivor. +// Memory pool that represents the G1 survivor space class G1SurvivorPool : public G1MemoryPoolSuper { public: G1SurvivorPool(G1CollectedHeap* g1h, size_t initial_size); - size_t used_in_bytes() { return _g1mm->survivor_space_used(); } - MemoryUsage get_memory_usage(); }; -// Memory pool that represents the G1 old gen. -class G1OldGenPool : public G1MemoryPoolSuper { +// Memory pool that represents the G1 old generation (legacy) +// or G1 old space (default) +class G1OldPool : public G1MemoryPoolSuper { public: - G1OldGenPool(G1CollectedHeap* g1h, size_t initial_size, size_t max_size); + G1OldPool(G1CollectedHeap* g1h, size_t initial_size, size_t max_size); + size_t used_in_bytes() { return _g1mm->old_space_used(); } + MemoryUsage get_memory_usage(); +}; - size_t used_in_bytes() { return _g1mm->old_gen_used(); } +// The default model includes the three legacy pools plus G1ArchivePool +// and G1HumongousPool, and G1OldPool does not include regions occupied +// by humongous and archive objects. Instead, humongous and archive +// objects each get their own pool. + +// Memory pool that represents the G1 archive space. The archive space +// contains read-only class metadata from the class data sharing archives. +class G1ArchivePool : public G1MemoryPoolSuper { +public: + G1ArchivePool(G1CollectedHeap* g1h, size_t initial_size); + size_t used_in_bytes() { return _g1mm->archive_space_used(); } + MemoryUsage get_memory_usage(); +}; +// Memory pool that represents the G1 humongous space +class G1HumongousPool : public G1MemoryPoolSuper { +public: + G1HumongousPool(G1CollectedHeap* g1h, size_t initial_size); + size_t used_in_bytes() { return _g1mm->humongous_space_used(); } MemoryUsage get_memory_usage(); }; --- old/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp 2018-10-18 18:02:00.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp 2018-10-18 18:01:59.000000000 -0400 @@ -60,7 +60,7 @@ virtual void update_all() { size_t committed = - G1MonitoringSupport::pad_capacity(_g1mm->young_gen_committed(), 3); + G1MonitoringSupport::pad_capacity(_g1mm->young_gen_committed(), 3); _current_size->set_value(committed); } }; @@ -79,43 +79,60 @@ virtual void update_all() { size_t committed = - G1MonitoringSupport::pad_capacity(_g1mm->old_gen_committed()); + G1MonitoringSupport::pad_capacity(_g1mm->old_gen_committed()); _current_size->set_value(committed); } }; +size_t G1MonitoringSupport::old_gen_committed() { + return _old_space_committed + + (use_legacy_monitoring() ? 0 : _humongous_space_committed + _archive_space_committed); +} + +size_t G1MonitoringSupport::old_gen_used() { + return old_space_used() + + (use_legacy_monitoring() ? 0 : humongous_space_used() + archive_space_used()); +} + G1MonitoringSupport::G1MonitoringSupport(G1CollectedHeap* g1h) : _g1h(g1h), + _use_legacy_monitoring(G1UseLegacyMonitoring), + + _full_memory_manager(G1UseLegacyMonitoring ? "G1 Old Generation" : "G1 Full", "end of major GC"), _incremental_memory_manager("G1 Young Generation", "end of minor GC"), - _full_gc_memory_manager("G1 Old Generation", "end of major GC"), + _young_memory_manager("G1 Young", "end of young GC"), + _mixed_memory_manager("G1 Mixed", "end of mixed GC"), + _conc_memory_manager("G1 Concurrent Cycle", "end of concurrent cycle"), + _eden_space_pool(NULL), _survivor_space_pool(NULL), - _old_gen_pool(NULL), + _old_space_pool(NULL), + _archive_space_pool(NULL), + _humongous_space_pool(NULL), + _incremental_collection_counters(NULL), _full_collection_counters(NULL), _conc_collection_counters(NULL), - _young_gen_counters(NULL), - _old_gen_counters(NULL), - _old_space_counters(NULL), - _eden_space_counters(NULL), - _from_space_counters(NULL), - _to_space_counters(NULL), - _overall_committed(0), - _overall_used(0), + _young_gen_counters(NULL), _old_gen_counters(NULL), + + _old_space_counters(NULL), _eden_space_counters(NULL), + _from_space_counters(NULL), _to_space_counters(NULL), + + _overall_committed(0), _overall_used(0), _young_gen_committed(0), - _old_gen_committed(0), + _eden_space_committed(0), _eden_space_used(0), + _survivor_space_committed(0), _survivor_space_used(0), + _old_space_committed(0), _old_space_used(0), + _archive_space_committed(0), _archive_space_used(0), + _humongous_space_committed(0), _humongous_space_used(0) { - _eden_space_committed(0), - _eden_space_used(0), - _survivor_space_committed(0), - _survivor_space_used(0), - _old_gen_used(0) { + // Counters for garbage collections. + // Compute initial capacities. Somewhat random, as they depend + // on what's happened so far during JVM initialization. recalculate_sizes(); - // Counters for garbage collections - // // name "collector.0". In a generational collector this would be the // young generation collection. _incremental_collection_counters = @@ -143,7 +160,7 @@ _old_space_counters = new HSpaceCounters(_old_gen_counters->name_space(), "space", 0 /* ordinal */, pad_capacity(g1h->max_capacity()) /* max_capacity */, - pad_capacity(_old_gen_committed) /* init_capacity */); + pad_capacity(old_gen_committed()) /* init_capacity */); // Young collection set // name "generation.0". This is logically the young generation. @@ -185,40 +202,75 @@ G1MonitoringSupport::~G1MonitoringSupport() { delete _eden_space_pool; delete _survivor_space_pool; - delete _old_gen_pool; + delete _old_space_pool; + delete _archive_space_pool; + delete _humongous_space_pool; } void G1MonitoringSupport::initialize_serviceability() { _eden_space_pool = new G1EdenPool(_g1h, _eden_space_committed); _survivor_space_pool = new G1SurvivorPool(_g1h, _survivor_space_committed); - _old_gen_pool = new G1OldGenPool(_g1h, _old_gen_committed, _g1h->max_capacity()); + _old_space_pool = new G1OldPool(_g1h, _old_space_committed, _g1h->max_capacity()); + _archive_space_pool = new G1ArchivePool(_g1h, _archive_space_committed); + _humongous_space_pool = new G1HumongousPool(_g1h, _humongous_space_committed); + + // Pools must be added to each memory manager in the order specified + // below: TestMemoryMXBeansAndPoolsPresence.java expects them so. + + if (use_legacy_monitoring()) { + _incremental_memory_manager.add_pool(_eden_space_pool); + _incremental_memory_manager.add_pool(_survivor_space_pool); + // Incremental GCs can affect the humongous pool, but legacy behavior ignores it. + // _incremental_memory_manager.add_pool(_humongous_space_pool); + _incremental_memory_manager.add_pool(_old_space_pool, false /* always_affected_by_gc */); + } else { + _young_memory_manager.add_pool(_eden_space_pool); + _young_memory_manager.add_pool(_survivor_space_pool); + _young_memory_manager.add_pool(_humongous_space_pool); + + _mixed_memory_manager.add_pool(_eden_space_pool); + _mixed_memory_manager.add_pool(_survivor_space_pool); + _mixed_memory_manager.add_pool(_humongous_space_pool); + _mixed_memory_manager.add_pool(_old_space_pool); - _full_gc_memory_manager.add_pool(_eden_space_pool); - _full_gc_memory_manager.add_pool(_survivor_space_pool); - _full_gc_memory_manager.add_pool(_old_gen_pool); - - _incremental_memory_manager.add_pool(_eden_space_pool); - _incremental_memory_manager.add_pool(_survivor_space_pool); - _incremental_memory_manager.add_pool(_old_gen_pool, false /* always_affected_by_gc */); -} + _conc_memory_manager.add_pool(_humongous_space_pool); + _conc_memory_manager.add_pool(_old_space_pool); + } -MemoryUsage G1MonitoringSupport::memory_usage() { - MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); - return MemoryUsage(InitialHeapSize, _overall_used, _overall_committed, _g1h->max_capacity()); + _full_memory_manager.add_pool(_eden_space_pool); + _full_memory_manager.add_pool(_survivor_space_pool); + if (!use_legacy_monitoring()) { + _full_memory_manager.add_pool(_humongous_space_pool); + _full_memory_manager.add_pool(_archive_space_pool); + } + _full_memory_manager.add_pool(_old_space_pool); + + // Update pool and jstat counter content + update_sizes(); } GrowableArray G1MonitoringSupport::memory_managers() { - GrowableArray memory_managers(2); - memory_managers.append(&_incremental_memory_manager); - memory_managers.append(&_full_gc_memory_manager); + GrowableArray memory_managers(4); + if (use_legacy_monitoring()) { + memory_managers.append(&_incremental_memory_manager); + } else { + memory_managers.append(&_young_memory_manager); + memory_managers.append(&_mixed_memory_manager); + memory_managers.append(&_conc_memory_manager); + } + memory_managers.append(&_full_memory_manager); return memory_managers; } GrowableArray G1MonitoringSupport::memory_pools() { - GrowableArray memory_pools(3); + GrowableArray memory_pools(5); memory_pools.append(_eden_space_pool); memory_pools.append(_survivor_space_pool); - memory_pools.append(_old_gen_pool); + memory_pools.append(_old_space_pool); + if (!use_legacy_monitoring()) { + memory_pools.append(_humongous_space_pool); + memory_pools.append(_archive_space_pool); + } return memory_pools; } @@ -226,72 +278,89 @@ assert_heap_locked_or_at_safepoint(true); MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); - // Recalculate all the sizes from scratch. - uint young_list_length = _g1h->young_regions_count(); - uint survivor_list_length = _g1h->survivor_regions_count(); - assert(young_list_length >= survivor_list_length, "invariant"); - uint eden_list_length = young_list_length - survivor_list_length; + // Recalculate all sizes from scratch. + + uint eden_regions_count = _g1h->eden_regions_count(); + uint survivor_regions_count = _g1h->survivor_regions_count(); + uint young_regions_count = _g1h->young_regions_count(); + assert(young_regions_count == eden_regions_count + survivor_regions_count, "invariant"); + uint old_regions_count = _g1h->old_regions_count(); + uint archive_regions_count = _g1h->archive_regions_count(); + uint humongous_regions_count = _g1h->humongous_regions_count(); + // Max length includes any potential extensions to the young gen // we'll do when the GC locker is active. - uint young_list_max_length = _g1h->g1_policy()->young_list_max_length(); - assert(young_list_max_length >= survivor_list_length, "invariant"); - uint eden_list_max_length = young_list_max_length - survivor_list_length; + uint young_regions_count_max = _g1h->g1_policy()->young_list_max_length(); + assert(young_regions_count_max >= survivor_regions_count, "invariant"); + uint eden_regions_count_max = young_regions_count_max - survivor_regions_count; _overall_used = _g1h->used_unlocked(); - _eden_space_used = (size_t) eden_list_length * HeapRegion::GrainBytes; - _survivor_space_used = (size_t) survivor_list_length * HeapRegion::GrainBytes; - _old_gen_used = subtract_up_to_zero(_overall_used, _eden_space_used + _survivor_space_used); + _eden_space_used = (size_t)eden_regions_count * HeapRegion::GrainBytes; + _survivor_space_used = (size_t)survivor_regions_count * HeapRegion::GrainBytes; + _archive_space_used = (size_t)archive_regions_count * HeapRegion::GrainBytes; + _humongous_space_used = (size_t)humongous_regions_count * HeapRegion::GrainBytes; + + // We separately keep track of the humongous and archive spaces, no + // matter which mode we're in. In legacy mode, the old space is the + // sum of the old, humongous and archive spaces, but in default mode + // it does not include the humongous and archive spaces. The old + // generation as a whole (in contrast to the old space), always + // includes the humongous and archive spaces. See the definitions of + // old_gen_committed() and old_gen_used(). + size_t excess_old = use_legacy_monitoring() ? 0 : _humongous_space_used + _archive_space_used; + _old_space_used = subtract_up_to_zero(_overall_used, _eden_space_used + _survivor_space_used + excess_old); - // First calculate the committed sizes that can be calculated independently. + // First, calculate the committed sizes that can be calculated independently. _survivor_space_committed = _survivor_space_used; - _old_gen_committed = HeapRegion::align_up_to_region_byte_size(_old_gen_used); - + _old_space_committed = HeapRegion::align_up_to_region_byte_size(_old_space_used); + _archive_space_committed = _archive_space_used; + _humongous_space_committed = _humongous_space_used; + // Next, start with the overall committed size. - _overall_committed = _g1h->capacity(); - size_t committed = _overall_committed; + size_t committed = _overall_committed = _g1h->capacity(); // Remove the committed size we have calculated so far (for the - // survivor and old space). - assert(committed >= (_survivor_space_committed + _old_gen_committed), "sanity"); - committed -= _survivor_space_committed + _old_gen_committed; - + // survivor, old, archive, and humongous spaces). + assert(committed >= (_survivor_space_committed + _old_space_committed + excess_old), "sanity"); + committed -= _survivor_space_committed + _old_space_committed + excess_old; + // Next, calculate and remove the committed size for the eden. - _eden_space_committed = (size_t) eden_list_max_length * HeapRegion::GrainBytes; + _eden_space_committed = (size_t)eden_regions_count_max * HeapRegion::GrainBytes; // Somewhat defensive: be robust in case there are inaccuracies in // the calculations _eden_space_committed = MIN2(_eden_space_committed, committed); committed -= _eden_space_committed; // Finally, give the rest to the old space... - _old_gen_committed += committed; + _old_space_committed += committed; // ..and calculate the young gen committed. _young_gen_committed = _eden_space_committed + _survivor_space_committed; assert(_overall_committed == - (_eden_space_committed + _survivor_space_committed + _old_gen_committed), + (_eden_space_committed + _survivor_space_committed + _old_space_committed + excess_old), "the committed sizes should add up"); // Somewhat defensive: cap the eden used size to make sure it // never exceeds the committed size. _eden_space_used = MIN2(_eden_space_used, _eden_space_committed); - // _survivor_committed and _old_committed are calculated in terms of - // the corresponding _*_used value, so the next two conditions - // should hold. + + // _survivor_space_committed and _old_space_committed are calculated in terms of + // the corresponding _*_used value, so the next two conditions should hold. assert(_survivor_space_used <= _survivor_space_committed, "post-condition"); - assert(_old_gen_used <= _old_gen_committed, "post-condition"); + assert(_old_space_used <= _old_space_committed, "post-condition"); } void G1MonitoringSupport::update_sizes() { recalculate_sizes(); if (UsePerfData) { _eden_space_counters->update_capacity(pad_capacity(_eden_space_committed)); - _eden_space_counters->update_used(_eden_space_used); - // only the "to" survivor space is active, so we don't need to + _eden_space_counters->update_used(eden_space_used()); + // only the "to" survivor space is active, so we don't need to // update the counters for the "from" survivor space _to_space_counters->update_capacity(pad_capacity(_survivor_space_committed)); - _to_space_counters->update_used(_survivor_space_used); - _old_space_counters->update_capacity(pad_capacity(_old_gen_committed)); - _old_space_counters->update_used(_old_gen_used); + _to_space_counters->update_used(survivor_space_used()); + _old_space_counters->update_capacity(pad_capacity(old_gen_committed())); + _old_space_counters->update_used(old_gen_used()); _young_gen_counters->update_all(); _old_gen_counters->update_all(); @@ -302,43 +371,97 @@ } void G1MonitoringSupport::update_eden_size() { - // Recalculate everything - this should be fast enough and we are sure that we do not - // miss anything. + // Recalculate everything. Should be fast enough and we are sure not to miss anything. recalculate_sizes(); if (UsePerfData) { - _eden_space_counters->update_used(_eden_space_used); + _eden_space_counters->update_capacity(pad_capacity(_eden_space_committed)); + _eden_space_counters->update_used(eden_space_used()); } } -MemoryUsage G1MonitoringSupport::eden_space_memory_usage(size_t initial_size, size_t max_size) { +MemoryUsage G1MonitoringSupport::memory_usage() { MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(InitialHeapSize, _overall_used, _overall_committed, _g1h->max_capacity()); +} - return MemoryUsage(initial_size, - _eden_space_used, - _eden_space_committed, - max_size); +MemoryUsage G1MonitoringSupport::eden_space_memory_usage(size_t initial_size, size_t max_size) { + MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(initial_size, eden_space_used(), _eden_space_committed, max_size); } MemoryUsage G1MonitoringSupport::survivor_space_memory_usage(size_t initial_size, size_t max_size) { MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(initial_size, survivor_space_used(), _survivor_space_committed, max_size); +} - return MemoryUsage(initial_size, - _survivor_space_used, - _survivor_space_committed, - max_size); +MemoryUsage G1MonitoringSupport::old_space_memory_usage(size_t initial_size, size_t max_size) { + MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(initial_size, old_space_used(), _old_space_committed, max_size); } -MemoryUsage G1MonitoringSupport::old_gen_memory_usage(size_t initial_size, size_t max_size) { +MemoryUsage G1MonitoringSupport::archive_space_memory_usage(size_t initial_size, size_t max_size) { MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(initial_size, archive_space_used(), _archive_space_committed, max_size); +} - return MemoryUsage(initial_size, - _old_gen_used, - _old_gen_committed, - max_size); +MemoryUsage G1MonitoringSupport::humongous_space_memory_usage(size_t initial_size, size_t max_size) { + MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); + return MemoryUsage(initial_size, humongous_space_used(), _humongous_space_committed, max_size); +} + +TraceConcMemoryManagerStats::TraceConcMemoryManagerStats(Stage stage, GCCause::Cause cause) + : TraceMemoryManagerStats() { + GCMemoryManager* manager = G1CollectedHeap::heap()->g1mm()->conc_memory_manager(); + switch (stage) { + case CycleStart: + initialize(manager /* GC manager */, + cause /* cause of the GC */, + true /* allMemoryPoolsAffected */, + true /* recordGCBeginTime */, + true /* recordPreGCUsage */, + false /* recordPeakUsage */, + false /* recordPostGCusage */, + false /* recordAccumulatedGCTime */, + false /* recordGCEndTime */, + false /* countCollection */ ); + break; + case Remark: + case Cleanup: + initialize(manager /* GC manager */, + cause /* cause of the GC */, + true /* allMemoryPoolsAffected */, + false /* recordGCBeginTime */, + false /* recordPreGCUsage */, + false /* recordPeakUsage */, + false /* recordPostGCusage */, + true /* recordAccumulatedGCTime */, + false /* recordGCEndTime */, + false /* countCollection */ ); + break; + case CycleEnd: + initialize(manager /* GC manager */, + cause /* cause of the GC */, + true /* allMemoryPoolsAffected */, + false /* recordGCBeginTime */, + false /* recordPreGCUsage */, + true /* recordPeakUsage */, + true /* recordPostGCusage */, + false /* recordAccumulatedGCTime */, + true /* recordGCEndTime */, + true /* countCollection */ ); + break; + default: + ShouldNotReachHere(); + break; + } } -G1MonitoringScope::G1MonitoringScope(G1MonitoringSupport* g1mm, bool full_gc, bool all_memory_pools_affected) : +G1MonitoringScope::G1MonitoringScope(G1MonitoringSupport* g1mm, bool full_gc, bool mixed_gc) : _tcs(full_gc ? g1mm->_full_collection_counters : g1mm->_incremental_collection_counters), - _tms(full_gc ? &g1mm->_full_gc_memory_manager : &g1mm->_incremental_memory_manager, - G1CollectedHeap::heap()->gc_cause(), all_memory_pools_affected) { + _tms(full_gc ? &g1mm->_full_memory_manager : + (g1mm->use_legacy_monitoring() ? &g1mm->_incremental_memory_manager : + (mixed_gc ? &g1mm->_mixed_memory_manager : + /* young */ &g1mm->_young_memory_manager)), + g1mm->_g1h->gc_cause(), + full_gc || (g1mm->use_legacy_monitoring() ? mixed_gc : true) /* allMemoryPoolsAffected */) { } --- old/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp 2018-10-18 18:02:01.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp 2018-10-18 18:02:00.000000000 -0400 @@ -46,20 +46,23 @@ // * survivors : regions with objects that survived the last few GCs // * old : long-lived non-humongous regions // * humongous : humongous regions +// * archive : archive regions // * free : free regions // // The combination of eden and survivor regions form the equivalent of -// the young generation in the other GCs. The combination of old and -// humongous regions form the equivalent of the old generation in the -// other GCs. Free regions do not have a good equivalent in the other -// GCs given that they can be allocated as any of the other region types. -// -// The monitoring tools expect the heap to contain a number of -// generations (young, old, perm) and each generation to contain a -// number of spaces (young: eden, survivors, old). Given that G1 does -// not maintain those spaces physically (e.g., the set of -// non-contiguous eden regions can be considered as a "logical" -// space), we'll provide the illusion that those generations and +// the young generation in the other GCs. The combination of old, +// humongous, and archive regions form the equivalent of the old +// generation in the other GCs. Archive regions are permanently +// allocated during heap initialization, e.g., for CDS. Free regions +// do not have a good equivalent in the other GCs, given that they can +// be allocated as any of the other region types. +// +// The monitoring tools expect the heap to contain one or more +// generations (young, old) and each generation to contain one or +// more spaces (young has eden and survivor, old has old, humongous and +// archive). Given that G1 does not maintain those spaces physically +// (e.g., the set of non-contiguous eden regions can be considered as +// a "logical" space), we provide the illusion that those generations and // spaces exist. In reality, each generation and space refers to a set // of heap regions that are potentially non-contiguous. // @@ -78,21 +81,29 @@ // (i.e., young gen target capacity + max allowed expansion capacity) // - survivor_capacity = current survivor region capacity // - eden_capacity = young_gen_capacity - survivor_capacity +// In legacy mode: // - old_capacity = heap_capacity - young_gen_capacity +// Otherwise: +// - humongous_capacity = sum of humongous regions allocated +// - archive_capacity = sum of archive regions allocated +// - old_capacity = heap_capacity - young_gen_capacity - +// humongous_capacity - archive_capacity // // What we do in the above is to distribute the free regions among // eden_capacity and old_capacity. // // * Occupancy // -// - young_gen_used = current young region capacity +// - young_gen_committed = current young region capacity // - survivor_used = survivor_capacity // - eden_used = young_gen_used - survivor_used +// In legacy mode: // - old_used = overall_used - young_gen_used -// -// Unfortunately, we currently only keep track of the number of -// currently allocated young and survivor regions + the overall used -// bytes in the heap, so the above can be a little inaccurate. +// Otherwise: +// - humongous_used = sum of humongous regions allocated +// - archive_used = sum of archive regions allocated +// - old_used = overall_used - young_gen_used - +// humongous_used - archive_used // // * Min Capacity // @@ -104,20 +115,18 @@ // given that we don't always have a reasonable upper bound on how big // each space can grow. For the memory pools, we make the max // capacity undefined with the exception of the old memory pool for -// which we make the max capacity same as the max heap capacity. -// -// If we had more accurate occupancy / capacity information per -// region set the above calculations would be greatly simplified and -// be made more accurate. +// which we make the max capacity same as the max heap capacity. This +// allows users to sum memory pool max capacities to get something +// reasonable. // // We update all the above synchronously and we store the results in -// fields so that we just read said fields when needed. A subtle point -// is that all the above sizes need to be recalculated when the old +// this singleton class so we can just read them out when needed. A subtle +// point is that all the above sizes must be recalculated when the old // gen changes capacity (after a GC or after a humongous allocation) // but only the eden occupancy changes when a new eden region is // allocated. So, in the latter case we have minimal recalculation to -// do which is important as we want to keep the eden region allocation -// path as low-overhead as possible. +// do, but we don't both special-casing it because doing the full +// recalculation is quite fast. class G1MonitoringSupport : public CHeapObj { friend class VMStructs; @@ -126,12 +135,22 @@ G1CollectedHeap* _g1h; // java.lang.management MemoryManager and MemoryPool support + + bool _use_legacy_monitoring; // For vmStructs and hsdb + + GCMemoryManager _full_memory_manager; + // Legacy monitoring GCMemoryManager _incremental_memory_manager; - GCMemoryManager _full_gc_memory_manager; + // Default monitoring + GCMemoryManager _young_memory_manager; + GCMemoryManager _mixed_memory_manager; + GCMemoryManager _conc_memory_manager; MemoryPool* _eden_space_pool; MemoryPool* _survivor_space_pool; - MemoryPool* _old_gen_pool; + MemoryPool* _old_space_pool; + MemoryPool* _archive_space_pool; + MemoryPool* _humongous_space_pool; // jstat performance counters // incremental collections both young and mixed @@ -165,14 +184,19 @@ size_t _overall_used; size_t _young_gen_committed; - size_t _old_gen_committed; size_t _eden_space_committed; size_t _eden_space_used; size_t _survivor_space_committed; size_t _survivor_space_used; - size_t _old_gen_used; + size_t _old_space_committed; + size_t _old_space_used; + size_t _archive_space_committed; + size_t _archive_space_used; + + size_t _humongous_space_committed; + size_t _humongous_space_used; // It returns x - y if x > y, 0 otherwise. // As described in the comment above, some of the inputs to the @@ -189,21 +213,21 @@ } } - // Recalculate all the sizes. + // Recalculate all the space sizes. void recalculate_sizes(); - void recalculate_eden_size(); - public: G1MonitoringSupport(G1CollectedHeap* g1h); ~G1MonitoringSupport(); void initialize_serviceability(); - MemoryUsage memory_usage(); GrowableArray memory_managers(); GrowableArray memory_pools(); + bool use_legacy_monitoring() { return _use_legacy_monitoring; } + GCMemoryManager* conc_memory_manager() { return &_conc_memory_manager; } + // Unfortunately, the jstat tool assumes that no space has 0 // capacity. In our case, given that each space is logical, it's // possible that no regions will be allocated to it, hence to have 0 @@ -219,10 +243,11 @@ return size_bytes + MinObjAlignmentInBytes * mult; } - // Recalculate all the sizes from scratch and update all the jstat - // counters accordingly. + // Recalculate all the space sizes from scratch and update + // all jstat counters accordingly. void update_sizes(); - + // Recalculate all the space sizes from scratch, but update + // just the eden size and jstat counters. void update_eden_size(); CollectorCounters* conc_collection_counters() { @@ -235,28 +260,48 @@ // Tracing // Values may not be consistent wrt to each other. - size_t young_gen_committed() { return _young_gen_committed; } + size_t young_gen_committed() { return _young_gen_committed; } + + size_t eden_space_used() { return _eden_space_used; } + size_t survivor_space_used() { return _survivor_space_used; } - size_t eden_space_used() { return _eden_space_used; } - size_t survivor_space_used() { return _survivor_space_used; } + size_t old_gen_committed(); + size_t old_gen_used(); - size_t old_gen_committed() { return _old_gen_committed; } - size_t old_gen_used() { return _old_gen_used; } + size_t old_space_committed() { return _old_space_committed; } + size_t old_space_used() { return _old_space_used; } + size_t archive_space_used() { return _archive_space_used; } + + size_t humongous_space_used() { return _humongous_space_used; } // Monitoring support for MemoryPools. Values in the returned MemoryUsage are // guaranteed to be consistent with each other. + MemoryUsage memory_usage(); MemoryUsage eden_space_memory_usage(size_t initial_size, size_t max_size); MemoryUsage survivor_space_memory_usage(size_t initial_size, size_t max_size); + MemoryUsage old_space_memory_usage(size_t initial_size, size_t max_size); + MemoryUsage archive_space_memory_usage(size_t initial_size, size_t max_size); + MemoryUsage humongous_space_memory_usage(size_t initial_size, size_t max_size); +}; - MemoryUsage old_gen_memory_usage(size_t initial_size, size_t max_size); +// TraceMemoryManagerStats for concurrent cycle. +class TraceConcMemoryManagerStats : public TraceMemoryManagerStats { + public: + enum Stage { + CycleStart, + Remark, + Cleanup, + CycleEnd + }; + TraceConcMemoryManagerStats(Stage stage, GCCause::Cause cause); }; // Scope object for java.lang.management support. class G1MonitoringScope : public StackObj { - TraceCollectorStats _tcs; + TraceCollectorStats _tcs; TraceMemoryManagerStats _tms; public: - G1MonitoringScope(G1MonitoringSupport* g1mm, bool full_gc, bool all_memory_pools_affected); + G1MonitoringScope(G1MonitoringSupport* g1mm, bool full_gc, bool mixed_gc); }; #endif // SHARE_VM_GC_G1_G1MONITORINGSUPPORT_HPP --- old/src/hotspot/share/gc/g1/g1_globals.hpp 2018-10-18 18:02:02.000000000 -0400 +++ new/src/hotspot/share/gc/g1/g1_globals.hpp 2018-10-18 18:02:02.000000000 -0400 @@ -302,6 +302,10 @@ "Verify the code root lists attached to each heap region.") \ \ develop(bool, G1VerifyBitmaps, false, \ - "Verifies the consistency of the marking bitmaps") + "Verifies the consistency of the marking bitmaps") \ + \ + product(bool, G1UseLegacyMonitoring, false, \ + "Use legacy GarbageCollector/MemoryPool MXBean and jstat " \ + "counter definitions") #endif // SHARE_VM_GC_G1_G1_GLOBALS_HPP --- old/src/hotspot/share/gc/g1/vmStructs_g1.hpp 2018-10-18 18:02:03.000000000 -0400 +++ new/src/hotspot/share/gc/g1/vmStructs_g1.hpp 2018-10-18 18:02:03.000000000 -0400 @@ -59,12 +59,17 @@ nonstatic_field(G1CollectedHeap, _archive_set, HeapRegionSetBase) \ nonstatic_field(G1CollectedHeap, _humongous_set, HeapRegionSetBase) \ \ + nonstatic_field(G1MonitoringSupport, _use_legacy_monitoring, bool) \ nonstatic_field(G1MonitoringSupport, _eden_space_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _eden_space_used, size_t) \ nonstatic_field(G1MonitoringSupport, _survivor_space_committed, size_t) \ nonstatic_field(G1MonitoringSupport, _survivor_space_used, size_t) \ - nonstatic_field(G1MonitoringSupport, _old_gen_committed, size_t) \ - nonstatic_field(G1MonitoringSupport, _old_gen_used, size_t) \ + nonstatic_field(G1MonitoringSupport, _old_space_committed, size_t) \ + nonstatic_field(G1MonitoringSupport, _old_space_used, size_t) \ + nonstatic_field(G1MonitoringSupport, _archive_space_committed, size_t) \ + nonstatic_field(G1MonitoringSupport, _archive_space_used, size_t) \ + nonstatic_field(G1MonitoringSupport, _humongous_space_committed,size_t) \ + nonstatic_field(G1MonitoringSupport, _humongous_space_used, size_t) \ \ nonstatic_field(HeapRegionSetBase, _length, uint) \ \ --- old/src/hotspot/share/services/memoryManager.cpp 2018-10-18 18:02:04.000000000 -0400 +++ new/src/hotspot/share/services/memoryManager.cpp 2018-10-18 18:02:04.000000000 -0400 @@ -210,7 +210,9 @@ void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, bool recordAccumulatedGCTime) { - assert(_last_gc_stat != NULL && _current_gc_stat != NULL, "Just checking"); + // Inactive memory managers (concurrent in G1 legacy mode) will not be initialized. + if (_last_gc_stat == NULL && _current_gc_stat == NULL) return; + if (recordAccumulatedGCTime) { _accumulated_timer.start(); } @@ -243,6 +245,8 @@ bool recordGCEndTime, bool countCollection, GCCause::Cause cause, bool allMemoryPoolsAffected) { + if (_last_gc_stat == NULL && _current_gc_stat == NULL) return; + if (recordAccumulatedGCTime) { _accumulated_timer.stop(); } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java 2018-10-18 18:02:05.000000000 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1MonitoringSupport.java 2018-10-18 18:02:05.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2018, 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 @@ -37,6 +37,8 @@ // Mirror class for G1MonitoringSupport. public class G1MonitoringSupport extends VMObject { + // bool _use_legacy_monitoring; + static private CIntegerField useLegacyMonitoringField; // size_t _eden_space_committed; static private CIntegerField edenSpaceCommittedField; // size_t _eden_space_used; @@ -45,10 +47,18 @@ static private CIntegerField survivorSpaceCommittedField; // size_t _survivor_space_used; static private CIntegerField survivorSpaceUsedField; - // size_t _old_gen_committed; - static private CIntegerField oldGenCommittedField; - // size_t _old_gen_used; - static private CIntegerField oldGenUsedField; + // size_t _old_space_committed; + static private CIntegerField oldSpaceCommittedField; + // size_t _old_space_used; + static private CIntegerField oldSpaceUsedField; + // size_t _archive_space_committed; + static private CIntegerField archiveSpaceCommittedField; + // size_t _archive_space_used; + static private CIntegerField archiveSpaceUsedField; + // size_t _humongous_space_committed; + static private CIntegerField humongousSpaceCommittedField; + // size_t _humongous_space_used; + static private CIntegerField humongousSpaceUsedField; static { VM.registerVMInitializedObserver(new Observer() { @@ -61,12 +71,21 @@ static private synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("G1MonitoringSupport"); + useLegacyMonitoringField = type.getCIntegerField("_use_legacy_monitoring"); edenSpaceCommittedField = type.getCIntegerField("_eden_space_committed"); edenSpaceUsedField = type.getCIntegerField("_eden_space_used"); survivorSpaceCommittedField = type.getCIntegerField("_survivor_space_committed"); survivorSpaceUsedField = type.getCIntegerField("_survivor_space_used"); - oldGenCommittedField = type.getCIntegerField("_old_gen_committed"); - oldGenUsedField = type.getCIntegerField("_old_gen_used"); + oldSpaceCommittedField = type.getCIntegerField("_old_space_committed"); + oldSpaceUsedField = type.getCIntegerField("_old_space_used"); + archiveSpaceCommittedField = type.getCIntegerField("_archive_space_committed"); + archiveSpaceUsedField = type.getCIntegerField("_archive_space_used"); + humongousSpaceCommittedField = type.getCIntegerField("_humongous_space_committed"); + humongousSpaceUsedField = type.getCIntegerField("_humongous_space_used"); + } + + public boolean useLegacyMonitoring() { + return useLegacyMonitoringField.getValue(addr) != 0; } public long edenSpaceCommitted() { @@ -93,12 +112,40 @@ return survivorSpaceUsed() / HeapRegion.grainBytes(); } - public long oldGenCommitted() { - return oldGenCommittedField.getValue(addr); + public long oldSpaceCommitted() { + return oldSpaceCommittedField.getValue(addr); + } + + public long oldSpaceUsed() { + return oldSpaceUsedField.getValue(addr); + } + + public long oldSpaceRegionNum() { + return oldSpaceUsed() / HeapRegion.grainBytes(); + } + + public long archiveSpaceCommitted() { + return archiveSpaceCommittedField.getValue(addr); + } + + public long archiveSpaceUsed() { + return archiveSpaceUsedField.getValue(addr); + } + + public long archiveSpaceRegionNum() { + return archiveSpaceUsed() / HeapRegion.grainBytes(); + } + + public long humongousSpaceCommitted() { + return humongousSpaceCommittedField.getValue(addr); + } + + public long humongousSpaceUsed() { + return humongousSpaceUsedField.getValue(addr); } - public long oldGenUsed() { - return oldGenUsedField.getValue(addr); + public long humongousSpaceRegionNum() { + return humongousSpaceUsed() / HeapRegion.grainBytes(); } public G1MonitoringSupport(Address addr) { --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java 2018-10-18 18:02:06.000000000 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java 2018-10-18 18:02:06.000000000 -0400 @@ -225,21 +225,24 @@ public void printG1HeapSummary(G1CollectedHeap g1h) { G1MonitoringSupport g1mm = g1h.g1mm(); - long edenSpaceRegionNum = g1mm.edenSpaceRegionNum(); - long survivorSpaceRegionNum = g1mm.survivorSpaceRegionNum(); - HeapRegionSetBase oldSet = g1h.oldSet(); - HeapRegionSetBase archiveSet = g1h.archiveSet(); - HeapRegionSetBase humongousSet = g1h.humongousSet(); - long oldGenRegionNum = oldSet.length() + archiveSet.length() + humongousSet.length(); - printG1Space("G1 Heap:", g1h.n_regions(), - g1h.used(), g1h.capacity()); + printG1Space("G1 Heap:", g1h.n_regions(), g1h.used(), g1h.capacity()); System.out.println("G1 Young Generation:"); - printG1Space("Eden Space:", edenSpaceRegionNum, + printG1Space("Eden Space:", g1mm.edenSpaceRegionNum(), g1mm.edenSpaceUsed(), g1mm.edenSpaceCommitted()); - printG1Space("Survivor Space:", survivorSpaceRegionNum, + printG1Space("Survivor Space:", g1mm.survivorSpaceRegionNum(), g1mm.survivorSpaceUsed(), g1mm.survivorSpaceCommitted()); - printG1Space("G1 Old Generation:", oldGenRegionNum, - g1mm.oldGenUsed(), g1mm.oldGenCommitted()); + if (g1mm.useLegacyMonitoring()) { + printG1Space("G1 Old Generation:", g1mm.oldSpaceRegionNum(), + g1mm.oldSpaceUsed(), g1mm.oldSpaceCommitted()); + } else { + System.out.println("G1 Old Generation:"); + printG1Space("G1 Old Space:", g1mm.oldSpaceRegionNum(), + g1mm.oldSpaceUsed(), g1mm.oldSpaceCommitted()); + printG1Space("G1 Archive Space:", g1mm.archiveSpaceRegionNum(), + g1mm.archiveSpaceUsed(), g1mm.archiveSpaceCommitted()); + printG1Space("G1 Humongous Space:", g1mm.humongousSpaceRegionNum(), + g1mm.humongousSpaceUsed(), g1mm.humongousSpaceCommitted()); + } } private void printG1Space(String spaceName, long regionNum, --- old/test/hotspot/jtreg/gc/TestMemoryMXBeansAndPoolsPresence.java 2018-10-18 18:02:08.000000000 -0400 +++ new/test/hotspot/jtreg/gc/TestMemoryMXBeansAndPoolsPresence.java 2018-10-18 18:02:07.000000000 -0400 @@ -34,7 +34,8 @@ * @modules java.base/jdk.internal.misc * java.management * @requires vm.gc == null - * @run main/othervm -XX:+UseG1GC TestMemoryMXBeansAndPoolsPresence G1 + * @run main/othervm -XX:+UseG1GC -XX:-G1UseLegacyMonitoring TestMemoryMXBeansAndPoolsPresence G1 NoLegacy + * @run main/othervm -XX:+UseG1GC -XX:+G1UseLegacyMonitoring TestMemoryMXBeansAndPoolsPresence G1 Legacy * @run main/othervm -XX:+UseParallelGC TestMemoryMXBeansAndPoolsPresence Parallel * @run main/othervm -XX:+UseSerialGC TestMemoryMXBeansAndPoolsPresence Serial */ @@ -86,8 +87,21 @@ public static void main(String[] args) { switch (args[0]) { case "G1": - test(new GCBeanDescription("G1 Young Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"}), - new GCBeanDescription("G1 Old Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"})); + if (args[1].equals("Legacy")) { + test(new GCBeanDescription("G1 Young Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"}), + new GCBeanDescription("G1 Old Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"})); + } else { + test(new GCBeanDescription("G1 Young", + new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Humongous Space"}), + new GCBeanDescription("G1 Mixed", + new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Humongous Space", + "G1 Old Space"}), + new GCBeanDescription("G1 Full", + new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Humongous Space", + "G1 Archive Space", "G1 Old Space"}), + new GCBeanDescription("G1 Concurrent Cycle", + new String[] {"G1 Humongous Space", "G1 Old Space"})); + } break; case "CMS": test(new GCBeanDescription("ParNew", new String[] {"Par Eden Space", "Par Survivor Space"}), --- old/test/hotspot/jtreg/gc/arguments/GCTypes.java 2018-10-18 18:02:09.000000000 -0400 +++ new/test/hotspot/jtreg/gc/arguments/GCTypes.java 2018-10-18 18:02:08.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, 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 @@ -26,6 +26,9 @@ import java.util.Arrays; import java.util.Objects; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + /** * Helper class with enum representation of GC types. */ @@ -57,12 +60,24 @@ .orElse(null); } + public static class LegacyMonitoring { + private static final boolean useLegacyMonitoring = getUseLegacyMonitoring(); + + private static boolean getUseLegacyMonitoring() { + HotSpotDiagnosticMXBean diagnostic + = ManagementFactory.getPlatformMXBean(HotSpotDiagnosticMXBean.class); + VMOption option = diagnostic.getVMOption("G1UseLegacyMonitoring"); + return option.getValue().equals("true"); + } + + public static boolean use() { return useLegacyMonitoring; } + } + /** * Helper interface used by GCTypes static methods * to get gcTypeName field of *GCType classes. */ private interface GCType { - String getGCName(); } @@ -70,7 +85,7 @@ DefNew("Copy"), ParNew("ParNew"), PSNew("PS Scavenge"), - G1("G1 Young Generation"); + G1("G1"); @Override public String getGCName() { @@ -79,6 +94,9 @@ private final String gcTypeName; private YoungGCType(String name) { + if (name.contains("G1")) { + name = LegacyMonitoring.use() ? "G1 Young Generation" : "G1 Young"; + } gcTypeName = name; } @@ -95,11 +113,14 @@ Serial("MarkSweepCompact"), CMS("ConcurrentMarkSweep"), PSOld("PS MarkSweep"), - G1("G1 Old Generation"); + G1("G1"); private final String gcTypeName; private OldGCType(String name) { + if (name.contains("G1")) { + name = LegacyMonitoring.use() ? "G1 Old Generation" : "G1 Full"; + } gcTypeName = name; } --- old/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java 2018-10-18 18:02:10.000000000 -0400 +++ new/test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java 2018-10-18 18:02:10.000000000 -0400 @@ -33,7 +33,8 @@ * @modules java.management * @build sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx14m -Xms14m -XX:MaxTenuringThreshold=1 -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 TestOldGenCollectionUsage + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:-G1UseLegacyMonitoring -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx12m -Xms12m -XX:MaxTenuringThreshold=1 -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 TestOldGenCollectionUsage + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+G1UseLegacyMonitoring -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx12m -Xms12m -XX:MaxTenuringThreshold=1 -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 TestOldGenCollectionUsage */ import jdk.test.lib.Asserts; @@ -50,8 +51,10 @@ public class TestOldGenCollectionUsage { - private String poolName = "G1 Old Gen"; - private String collectorName = "G1 Young Generation"; + private String poolName; + private String youngCollectorName; + private String mixedCollectorName; + private boolean useLegacyMonitoring; public static void main(String [] args) throws Exception { TestOldGenCollectionUsage t = new TestOldGenCollectionUsage(); @@ -59,11 +62,23 @@ } public TestOldGenCollectionUsage() { - System.out.println("Monitor G1 Old Gen pool with G1 Young Generation collector."); + useLegacyMonitoring = LegacyMonitoring.use(); + poolName = useLegacyMonitoring ? "G1 Old Gen" : "G1 Old Space"; + youngCollectorName = useLegacyMonitoring ? "G1 Young Generation" : "G1 Young"; + mixedCollectorName = useLegacyMonitoring ? "G1 Young Generation" : "G1 Mixed"; + System.out.println("Monitor G1 Old Gen pool with " + mixedCollectorName + " collector."); + } + + public static class LegacyMonitoring { + private static final boolean useLegacyMonitoring = getUseLegacyMonitoring(); + private static boolean getUseLegacyMonitoring() { + return ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-XX:+G1UseLegacyMonitoring"); + } + public static boolean use() { return useLegacyMonitoring; } } public void run() { - // Find memory pool and collector + // Find old space memory pool and collectors List pools = ManagementFactory.getMemoryPoolMXBeans(); MemoryPoolMXBean pool = null; boolean foundPool = false; @@ -81,45 +96,52 @@ } List collectors = ManagementFactory.getGarbageCollectorMXBeans(); - GarbageCollectorMXBean collector = null; - boolean foundCollector = false; + GarbageCollectorMXBean youngCollector = null; + GarbageCollectorMXBean mixedCollector = null; for (int i = 0; i < collectors.size(); i++) { - collector = collectors.get(i); + GarbageCollectorMXBean collector = collectors.get(i); String name = collector.getName(); - if (name.contains(collectorName)) { - System.out.println("Found collector: " + name); - foundCollector = true; - break; + if (name.equals(youngCollectorName)) { + System.out.println("Found young collector: " + name); + youngCollector = collector; + } + if (name.equals(mixedCollectorName)) { + System.out.println("Found mixed collector: " + name); + mixedCollector = collector; } } - if (!foundCollector) { - throw new RuntimeException(collectorName + " not found, test with -XX:+UseG1GC"); + if (youngCollector == null) { + throw new RuntimeException(youngCollectorName + " not found, test with -XX:+UseG1GC"); + } + if (mixedCollector == null) { + throw new RuntimeException(mixedCollectorName + " not found, test with -XX:+UseG1GC"); } MixedGCProvoker gcProvoker = new MixedGCProvoker(); gcProvoker.allocateOldObjects(); - // Verify no non-zero result was stored + // Verify no non-zero result was stored for the pool long usage = pool.getCollectionUsage().getUsed(); System.out.println(poolName + ": usage after GC = " + usage); if (usage > 0) { throw new RuntimeException("Premature mixed collections(s)"); } - // Verify that collections were done - long collectionCount = collector.getCollectionCount(); - System.out.println(collectorName + ": collection count = " - + collectionCount); - long collectionTime = collector.getCollectionTime(); - System.out.println(collectorName + ": collection time = " - + collectionTime); - if (collectionCount <= 0) { - throw new RuntimeException("Collection count <= 0"); + // Verify that young collections were done + long youngCollectionCount = youngCollector.getCollectionCount(); + System.out.println(youngCollectorName + ": collection count = " + + youngCollectionCount); + long youngCollectionTime = youngCollector.getCollectionTime(); + System.out.println(youngCollectorName + ": collection time = " + + youngCollectionTime); + if (youngCollectionCount <= 0) { + throw new RuntimeException("Young collection count <= 0"); } - if (collectionTime <= 0) { - throw new RuntimeException("Collector has not run"); + if (youngCollectionTime <= 0) { + throw new RuntimeException("Young collector did not run"); } + // Force promotion gcProvoker.provokeMixedGC(); usage = pool.getCollectionUsage().getUsed(); @@ -128,17 +150,23 @@ throw new RuntimeException(poolName + " found with zero usage"); } - long newCollectionCount = collector.getCollectionCount(); - System.out.println(collectorName + ": collection count = " + long newCollectionCount = mixedCollector.getCollectionCount(); + System.out.println(mixedCollectorName + ": collection count = " + newCollectionCount); - long newCollectionTime = collector.getCollectionTime(); - System.out.println(collectorName + ": collection time = " + long newCollectionTime = mixedCollector.getCollectionTime(); + System.out.println(mixedCollectorName + ": collection time = " + newCollectionTime); - if (newCollectionCount <= collectionCount) { - throw new RuntimeException("No new collection"); - } - if (newCollectionTime <= collectionTime) { - throw new RuntimeException("Collector has not run some more"); + if (useLegacyMonitoring) { + if (newCollectionCount <= youngCollectionCount) { + throw new RuntimeException("No new collection"); + } + } else { + if (newCollectionCount <= 0) { + throw new RuntimeException("Mixed collection count <= 0"); + } + if (newCollectionTime <= 0) { + throw new RuntimeException("Mixed collector did not run"); + } } System.out.println("Test passed."); --- old/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java 2018-10-18 18:02:11.000000000 -0400 +++ new/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java 2018-10-18 18:02:11.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, 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 @@ -24,14 +24,27 @@ /* * @test TestGCLockerWithG1 - * @key gc + * @key gc stress * @requires vm.gc.G1 * @summary Stress G1's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC TestGCLockerWithG1 + * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC -XX:-G1UseLegacyMonitoring TestGCLockerWithG1 + * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC -XX:+G1UseLegacyMonitoring TestGCLockerWithG1 */ + +import java.lang.management.RuntimeMXBean; +import java.lang.management.ManagementFactory; + public class TestGCLockerWithG1 { public static void main(String[] args) { - String[] testArgs = {"2", "G1 Old Gen"}; + String[] testArgs = {"2", LegacyMonitoring.use() ? "G1 Old Gen" : "G1 Old Space"}; TestGCLocker.main(testArgs); } + + public static class LegacyMonitoring { + private static final boolean useLegacyMonitoring = getUseLegacyMonitoring(); + private static boolean getUseLegacyMonitoring() { + return ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-XX:+G1UseLegacyMonitoring"); + } + public static boolean use() { return useLegacyMonitoring; } + } } --- old/test/hotspot/jtreg/gc/survivorAlignment/SurvivorAlignmentTestMain.java 2018-10-18 18:02:12.000000000 -0400 +++ new/test/hotspot/jtreg/gc/survivorAlignment/SurvivorAlignmentTestMain.java 2018-10-18 18:02:12.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2018, 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 @@ -71,7 +71,8 @@ private static final String SERIAL_TENURED = "Tenured Gen"; private static final String CMS_TENURED = "CMS Old Gen"; private static final String PS_TENURED = "PS Old Gen"; - private static final String G1_TENURED = "G1 Old Gen"; + private static final String G1_TENURED_LEGACY = "G1 Old Gen"; + private static final String G1_TENURED = "G1 Old Space"; private static final long G1_HEAP_REGION_SIZE = Optional.ofNullable( SurvivorAlignmentTestMain.WHITE_BOX.getUintxVMFlag( @@ -177,6 +178,7 @@ break; case SurvivorAlignmentTestMain.SERIAL_TENURED: case SurvivorAlignmentTestMain.PS_TENURED: + case SurvivorAlignmentTestMain.G1_TENURED_LEGACY: case SurvivorAlignmentTestMain.G1_TENURED: Asserts.assertNull(tenuredHelper, "Only one bean for tenured space is expected."); --- old/test/hotspot/jtreg/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java 2018-10-18 18:02:13.000000000 -0400 +++ new/test/hotspot/jtreg/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java 2018-10-18 18:02:13.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, 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 @@ -86,6 +86,7 @@ GCType = "-XX:+UseParallelGC"; break; case "G1 Old Generation": + case "G1 Full": GCType = "-XX:+UseG1GC"; break; } --- old/test/jdk/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 2018-10-18 18:02:15.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 2018-10-18 18:02:14.000000000 -0400 @@ -75,7 +75,8 @@ RunUtil.runTestKeepGcOpts(main); RunUtil.runTestClearGcOpts(main, "-XX:+UseSerialGC"); RunUtil.runTestClearGcOpts(main, "-XX:+UseParallelGC"); - RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC", "-XX:-G1UseLegacyMonitoring"); + RunUtil.runTestClearGcOpts(main, "-XX:+UseG1GC", "-XX:+G1UseLegacyMonitoring"); if (!Compiler.isGraalEnabled()) { // Graal does not support CMS RunUtil.runTestClearGcOpts(main, "-XX:+UseConcMarkSweepGC"); } --- old/test/jdk/java/lang/management/MemoryMXBean/LowMemoryTest.java 2018-10-18 18:02:16.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/LowMemoryTest.java 2018-10-18 18:02:16.000000000 -0400 @@ -83,9 +83,13 @@ // Runs the test collecting subprocess I/O while it's running. traceTest(classMain + ", -XX:+UseSerialGC", nmFlag, lpFlag, "-XX:+UseSerialGC"); traceTest(classMain + ", -XX:+UseParallelGC", nmFlag, lpFlag, "-XX:+UseParallelGC"); - traceTest(classMain + ", -XX:+UseG1GC", nmFlag, lpFlag, "-XX:+UseG1GC", g1Flag); + traceTest(classMain + ", -XX:+UseG1GC -XX:-G1UseLegacyMonitoring", nmFlag, lpFlag, + "-XX:+UseG1GC", "-XX:-G1UseLegacyMonitoring", g1Flag); + traceTest(classMain + ", -XX:+UseG1GC -XX:+G1UseLegacyMonitoring", nmFlag, lpFlag, + "-XX:+UseG1GC", "-XX:+G1UseLegacyMonitoring", g1Flag); if (!Compiler.isGraalEnabled()) { // Graal does not support CMS - traceTest(classMain + ", -XX:+UseConcMarkSweepGC", nmFlag, lpFlag, "-XX:+UseConcMarkSweepGC"); + traceTest(classMain + ", -XX:+UseConcMarkSweepGC", nmFlag, lpFlag, + "-XX:+UseConcMarkSweepGC"); } } @@ -232,17 +236,39 @@ ListIterator iter = pools.listIterator(); while (iter.hasNext()) { MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); + // Only check heap pools that support a usage threshold. + // This is typically only the old generation space + // since the other spaces are expected to get filled up. if (p.getType() == MemoryType.HEAP && p.isUsageThresholdSupported()) { - mpool = p; - if (trace) { - System.out.println("Selected memory pool for low memory " + - "detection."); - MemoryUtil.printMemoryPool(mpool); + // In all collectors except G1, only the old generation supports a + // usage threshold. The G1 legacy mode "G1 Old Gen" also does. In + // G1 default mode, both the old space ("G1 Old Space": it's not + // really a generation in the non-G1 collector sense) and the + // humongous space ("G1 Humongous Space"), support a usage threshold. + // So, the following condition is true for all non-G1 old generations, + // for the G1 legacy old gen, and for the G1 default humongous space. + // It is not true for the G1 default old gen. + // + // We're allocating humongous objects in this test, so the G1 default + // mode "G1 Old Space" occupancy doesn't change, because humongous + // objects are allocated in the "G1 Humongous Space". If we allowed + // the G1 default mode "G1 Old Space", notification would never + // happen because no objects are allocated there. + if (!p.getName().equals("G1 Old Space")) { + mpool = p; + if (trace) { + System.out.println("Selected memory pool for low memory " + + "detection."); + MemoryUtil.printMemoryPool(mpool); + } + break; } - break; } } + if (mpool == null) { + throw new RuntimeException("TEST FAILED: No heap pool found"); + } TestListener listener = new TestListener(); SensorListener l2 = new SensorListener(); --- old/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java 2018-10-18 18:02:17.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/MemoryManagement.java 2018-10-18 18:02:17.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -82,21 +82,43 @@ MemoryUtil.printMemoryManagers(managers); } - // Find the Old generation which supports low memory detection + // Find a pool which which supports low memory detection ListIterator iter = pools.listIterator(); while (iter.hasNext()) { MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); + // Only check heap pools that support a usage threshold. + // This is typically only the old generation space + // since the other spaces are expected to get filled up. if (p.getType() == MemoryType.HEAP && p.isUsageThresholdSupported()) { - mpool = p; - if (trace) { - System.out.println("Selected memory pool for low memory " + - "detection."); - MemoryUtil.printMemoryPool(mpool); + // In all collectors except G1, only the old generation supports a + // usage threshold. The G1 legacy mode "G1 Old Gen" also does. In + // G1 default mode, both the old space ("G1 Old Space": it's not + // really a generation in the non-G1 collector sense) and the + // humongous space ("G1 Humongous Space"), support a usage threshold. + // So, the following condition is true for all non-G1 old generations, + // for the G1 legacy old gen, and for the G1 default humongous space. + // It is not true for the G1 default old gen. + // + // We're allocating humongous objects in this test, so the G1 default + // mode "G1 Old Space" occupancy doesn't change, because humongous + // objects are allocated in the "G1 Humongous Space". If we allowed + // the G1 default mode "G1 Old Space", notification would never + // happen because no objects are allocated there. + if (!p.getName().equals("G1 Old Space")) { + mpool = p; + if (trace) { + System.out.println("Selected memory pool for low memory " + + "detection."); + MemoryUtil.printMemoryPool(mpool); + } + break; } - break; } } + if (mpool == null) { + throw new RuntimeException("TEST FAILED: No heap pool found"); + } SensorListener listener = new SensorListener(); NotificationEmitter emitter = (NotificationEmitter) mm; --- old/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java 2018-10-18 18:02:18.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/MemoryTest.java 2018-10-18 18:02:18.000000000 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, 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 @@ -30,7 +30,8 @@ * @author Mandy Chung * * @modules jdk.management - * @run main MemoryTest 2 3 + * @run main MemoryTest 4 5 + * @run main/othervm -XX:+UseParallelGC MemoryTest 2 3 */ /* --- old/test/jdk/java/lang/management/MemoryMXBean/MemoryTestAllGC.sh 2018-10-18 18:02:20.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/MemoryTestAllGC.sh 2018-10-18 18:02:19.000000000 -0400 @@ -1,5 +1,5 @@ # -# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2003, 2018, 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 @@ -49,7 +49,7 @@ } # Test MemoryTest with default collector -runOne MemoryTest 2 3 +runOne MemoryTest 4 5 # Test MemoryTest with parallel scavenger collector runOne -XX:+UseParallelGC MemoryTest 2 3 --- old/test/jdk/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java 2018-10-18 18:02:21.000000000 -0400 +++ new/test/jdk/java/lang/management/MemoryMXBean/ResetPeakMemoryUsage.java 2018-10-18 18:02:21.000000000 -0400 @@ -48,6 +48,7 @@ import java.util.*; import sun.hotspot.code.Compiler; +import sun.hotspot.WhiteBox; public class ResetPeakMemoryUsage { private static MemoryMXBean mbean = ManagementFactory.getMemoryMXBean(); @@ -67,9 +68,12 @@ RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseConcMarkSweepGC"); } RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseParallelGC"); - RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseG1GC", "-XX:G1HeapRegionSize=1m"); + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseG1GC", "-XX:-G1UseLegacyMonitoring", + "-XX:G1HeapRegionSize=1m"); + RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseG1GC", "-XX:+G1UseLegacyMonitoring", + "-XX:G1HeapRegionSize=1m"); RunUtil.runTestClearGcOpts(main, ms, mn, "-XX:+UseSerialGC", - "-XX:MarkSweepAlwaysCompactCount=1"); + "-XX:MarkSweepAlwaysCompactCount=1"); } private static class TestMain { @@ -79,14 +83,29 @@ boolean found = false; while (iter.hasNext()) { MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); - // only check heap pools that support usage threshold - // this is typically only the old generation space - // since the other spaces are expected to get filled up + // Only check heap pools that support a usage threshold. + // This is typically only the old generation space + // since the other spaces are expected to get filled up. if (p.getType() == MemoryType.HEAP && - p.isUsageThresholdSupported()) - { - found = true; - testPool(p); + p.isUsageThresholdSupported()) { + // In all collectors except G1, only the old generation supports a + // usage threshold. The G1 legacy mode "G1 Old Gen" also does. In + // G1 default mode, both the old space ("G1 Old Space": it's not + // really a generation in the non-G1 collector sense) and the + // humongous space ("G1 Humongous Space"), support a usage threshold. + // So, the following condition is true for all non-G1 old generations, + // for the G1 legacy old gen, and for the G1 default humongous space. + // It is not true for the G1 default old gen. + // + // We're allocating humongous objects in this test, so the G1 default + // mode "G1 Old Space" occupancy doesn't change, because humongous + // objects are allocated in the "G1 Humongous Space". If we allowed + // the G1 default mode "G1 Old Space", notification would never + // happen because no objects are allocated there. + if (!p.getName().equals("G1 Old Space")) { + found = true; + testPool(p); + } } } if (!found) { @@ -131,13 +150,11 @@ formatSize("After allocation: peak", peak1.getUsed())); } - - // The object is now garbage and do a GC - // memory usage should drop + // The object is now garbage and do a GC. Memory usage should drop. obj = null; - //This will cause sure shot GC unlike Runtime.gc() invoked by mbean.gc() - while(weakRef.get() != null) { + // This will cause a sure shot GC unlike Runtime.gc() invoked by mbean.gc() + while (weakRef.get() != null) { mbean.gc(); } --- old/test/jdk/jdk/jfr/event/gc/detailed/PromotionEvent.java 2018-10-18 18:02:22.000000000 -0400 +++ new/test/jdk/jdk/jfr/event/gc/detailed/PromotionEvent.java 2018-10-18 18:02:22.000000000 -0400 @@ -70,7 +70,8 @@ for (GarbageCollectorMXBean gcBean : gcBeans) { if ("PS Scavenge".equals(gcBean.getName()) || "G1 Young Generation".equals(gcBean.getName()) - || ("ParNew".equals(gcBean.getName()))) { + || "G1 Young".equals(gcBean.getName()) + || "ParNew".equals(gcBean.getName())) { ycBean = gcBean; } @@ -84,7 +85,7 @@ return; // To remove IDE warning } - System.gc(); // Clear nusery before recording + System.gc(); // Clear nursery before recording // Get total GC count before recording for (GarbageCollectorMXBean gcBean : gcBeans) { --- old/test/jdk/jdk/jfr/event/gc/stacktrace/AllocationStackTrace.java 2018-10-18 18:02:24.000000000 -0400 +++ new/test/jdk/jdk/jfr/event/gc/stacktrace/AllocationStackTrace.java 2018-10-18 18:02:23.000000000 -0400 @@ -305,7 +305,7 @@ * Tests event stacktrace for young GC if -XX:+UseG1GC is used */ public static void testG1YoungAllocEvent() throws Exception { - GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation"); + GarbageCollectorMXBean bean = g1YoungGarbageCollectorMXBean(); MemoryAllocator memory = new EdenMemoryAllocator(); String[] expectedStack = new String[]{ @@ -317,10 +317,10 @@ } /** - * Tests event stacktrace for old GC if -XX:+UseG1GC is used + * Tests event stacktrace for old/full GC if -XX:+UseG1GC is used */ public static void testG1OldAllocEvent() throws Exception { - GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Old Generation"); + GarbageCollectorMXBean bean = g1FullGarbageCollectorMXBean(); MemoryAllocator memory = new OldGenMemoryAllocator(); String[] expectedStack = new String[]{ @@ -336,7 +336,7 @@ * used */ public static void testMetaspaceG1GCAllocEvent() throws Exception { - GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation"); + GarbageCollectorMXBean bean = g1YoungGarbageCollectorMXBean(); MemoryAllocator memory = new MetaspaceMemoryAllocator(); String[] expectedStack = new String[]{ @@ -354,7 +354,7 @@ public static void testG1HumonAllocEvent() throws Exception { // G1 tries to reclaim humongous objects at every young collection // after doing a conservative estimate of its liveness - GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation"); + GarbageCollectorMXBean bean = g1YoungGarbageCollectorMXBean(); MemoryAllocator memory = new HumongousMemoryAllocator(); String[] expectedStack = new String[]{ @@ -367,8 +367,30 @@ private static GarbageCollectorMXBean garbageCollectorMXBean(String name) throws Exception { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - GarbageCollectorMXBean bean = ManagementFactory.newPlatformMXBeanProxy( - server, "java.lang:type=GarbageCollector,name=" + name, GarbageCollectorMXBean.class); + GarbageCollectorMXBean bean; + try { + bean = ManagementFactory.newPlatformMXBeanProxy(server, + "java.lang:type=GarbageCollector,name=" + name, + GarbageCollectorMXBean.class); + } catch (IllegalArgumentException e) { + bean = null; + } + return bean; + } + + private static GarbageCollectorMXBean g1YoungGarbageCollectorMXBean() throws Exception { + GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Young Generation"); + if (bean == null) { + bean = garbageCollectorMXBean("G1 Young"); + } + return bean; + } + + private static GarbageCollectorMXBean g1FullGarbageCollectorMXBean() throws Exception { + GarbageCollectorMXBean bean = garbageCollectorMXBean("G1 Old Generation"); + if (bean == null) { + bean = garbageCollectorMXBean("G1 Full"); + } return bean; } --- old/test/lib/jdk/test/lib/jfr/GCHelper.java 2018-10-18 18:02:25.000000000 -0400 +++ new/test/lib/jdk/test/lib/jfr/GCHelper.java 2018-10-18 18:02:25.000000000 -0400 @@ -35,6 +35,8 @@ import java.io.PrintStream; import java.lang.management.GarbageCollectorMXBean; import java.lang.management.ManagementFactory; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; @@ -171,12 +173,16 @@ static { // young GarbageCollectionMXBeans. beanCollectorTypes.put("G1 Young Generation", true); + beanCollectorTypes.put("G1 Young", true); beanCollectorTypes.put("Copy", true); beanCollectorTypes.put("PS Scavenge", true); beanCollectorTypes.put("ParNew", true); // old GarbageCollectionMXBeans. beanCollectorTypes.put("G1 Old Generation", false); + beanCollectorTypes.put("G1 Mixed", false); + beanCollectorTypes.put("G1 Concurrent Cycle", false); + beanCollectorTypes.put("G1 Full", false); beanCollectorTypes.put("ConcurrentMarkSweep", false); beanCollectorTypes.put("PS MarkSweep", false); beanCollectorTypes.put("MarkSweepCompact", false);