8195115: G1 Old Gen MemoryPool CollectionUsage.used values don't reflect mixed GC results
Memory pools can now be optional collection participants, e.g., G1 Old Gen in an incremental collection. Reviewed-by: ehelin, mchung
This commit is contained in:
parent
425e1a8bb8
commit
ebe240f3f4
@ -8088,6 +8088,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
|
|||||||
case CMSCollector::InitialMarking:
|
case CMSCollector::InitialMarking:
|
||||||
initialize(manager /* GC manager */ ,
|
initialize(manager /* GC manager */ ,
|
||||||
cause /* cause of the GC */,
|
cause /* cause of the GC */,
|
||||||
|
true /* allMemoryPoolsAffected */,
|
||||||
true /* recordGCBeginTime */,
|
true /* recordGCBeginTime */,
|
||||||
true /* recordPreGCUsage */,
|
true /* recordPreGCUsage */,
|
||||||
false /* recordPeakUsage */,
|
false /* recordPeakUsage */,
|
||||||
@ -8100,6 +8101,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
|
|||||||
case CMSCollector::FinalMarking:
|
case CMSCollector::FinalMarking:
|
||||||
initialize(manager /* GC manager */ ,
|
initialize(manager /* GC manager */ ,
|
||||||
cause /* cause of the GC */,
|
cause /* cause of the GC */,
|
||||||
|
true /* allMemoryPoolsAffected */,
|
||||||
false /* recordGCBeginTime */,
|
false /* recordGCBeginTime */,
|
||||||
false /* recordPreGCUsage */,
|
false /* recordPreGCUsage */,
|
||||||
false /* recordPeakUsage */,
|
false /* recordPeakUsage */,
|
||||||
@ -8112,6 +8114,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
|
|||||||
case CMSCollector::Sweeping:
|
case CMSCollector::Sweeping:
|
||||||
initialize(manager /* GC manager */ ,
|
initialize(manager /* GC manager */ ,
|
||||||
cause /* cause of the GC */,
|
cause /* cause of the GC */,
|
||||||
|
true /* allMemoryPoolsAffected */,
|
||||||
false /* recordGCBeginTime */,
|
false /* recordGCBeginTime */,
|
||||||
false /* recordPreGCUsage */,
|
false /* recordPreGCUsage */,
|
||||||
true /* recordPeakUsage */,
|
true /* recordPeakUsage */,
|
||||||
|
@ -1737,7 +1737,7 @@ void G1CollectedHeap::initialize_serviceability() {
|
|||||||
|
|
||||||
_memory_manager.add_pool(_eden_pool);
|
_memory_manager.add_pool(_eden_pool);
|
||||||
_memory_manager.add_pool(_survivor_pool);
|
_memory_manager.add_pool(_survivor_pool);
|
||||||
|
_memory_manager.add_pool(_old_pool, false /* always_affected_by_gc */);
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CollectedHeap::stop() {
|
void G1CollectedHeap::stop() {
|
||||||
@ -2833,7 +2833,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
|||||||
log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers());
|
log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers());
|
||||||
|
|
||||||
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
|
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
|
||||||
TraceMemoryManagerStats tms(&_memory_manager, gc_cause());
|
TraceMemoryManagerStats tms(&_memory_manager, gc_cause(),
|
||||||
|
collector_state()->yc_type() == Mixed /* allMemoryPoolsAffected */);
|
||||||
|
|
||||||
G1HeapTransition heap_transition(this);
|
G1HeapTransition heap_transition(this);
|
||||||
size_t heap_used_bytes_before_gc = used();
|
size_t heap_used_bytes_before_gc = used();
|
||||||
|
@ -43,13 +43,15 @@ MemoryManager::MemoryManager(const char* name) : _name(name) {
|
|||||||
(void)const_cast<instanceOop&>(_memory_mgr_obj = instanceOop(NULL));
|
(void)const_cast<instanceOop&>(_memory_mgr_obj = instanceOop(NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryManager::add_pool(MemoryPool* pool) {
|
int MemoryManager::add_pool(MemoryPool* pool) {
|
||||||
assert(_num_pools < MemoryManager::max_num_pools, "_num_pools exceeds the max");
|
int index = _num_pools;
|
||||||
if (_num_pools < MemoryManager::max_num_pools) {
|
assert(index < MemoryManager::max_num_pools, "_num_pools exceeds the max");
|
||||||
_pools[_num_pools] = pool;
|
if (index < MemoryManager::max_num_pools) {
|
||||||
|
_pools[index] = pool;
|
||||||
_num_pools++;
|
_num_pools++;
|
||||||
}
|
}
|
||||||
pool->add_manager(this);
|
pool->add_manager(this);
|
||||||
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryManager* MemoryManager::get_code_cache_memory_manager() {
|
MemoryManager* MemoryManager::get_code_cache_memory_manager() {
|
||||||
@ -189,6 +191,15 @@ GCMemoryManager::~GCMemoryManager() {
|
|||||||
delete _current_gc_stat;
|
delete _current_gc_stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GCMemoryManager::add_pool(MemoryPool* pool) {
|
||||||
|
add_pool(pool, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GCMemoryManager::add_pool(MemoryPool* pool, bool always_affected_by_gc) {
|
||||||
|
int index = MemoryManager::add_pool(pool);
|
||||||
|
_pool_always_affected_by_gc[index] = always_affected_by_gc;
|
||||||
|
}
|
||||||
|
|
||||||
void GCMemoryManager::initialize_gc_stat_info() {
|
void GCMemoryManager::initialize_gc_stat_info() {
|
||||||
assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools");
|
assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools");
|
||||||
_last_gc_stat = new(ResourceObj::C_HEAP, mtGC) GCStatInfo(MemoryService::num_memory_pools());
|
_last_gc_stat = new(ResourceObj::C_HEAP, mtGC) GCStatInfo(MemoryService::num_memory_pools());
|
||||||
@ -230,7 +241,8 @@ void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
|
|||||||
void GCMemoryManager::gc_end(bool recordPostGCUsage,
|
void GCMemoryManager::gc_end(bool recordPostGCUsage,
|
||||||
bool recordAccumulatedGCTime,
|
bool recordAccumulatedGCTime,
|
||||||
bool recordGCEndTime, bool countCollection,
|
bool recordGCEndTime, bool countCollection,
|
||||||
GCCause::Cause cause) {
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected) {
|
||||||
if (recordAccumulatedGCTime) {
|
if (recordAccumulatedGCTime) {
|
||||||
_accumulated_timer.stop();
|
_accumulated_timer.stop();
|
||||||
}
|
}
|
||||||
@ -259,9 +271,11 @@ void GCMemoryManager::gc_end(bool recordPostGCUsage,
|
|||||||
MemoryPool* pool = get_memory_pool(i);
|
MemoryPool* pool = get_memory_pool(i);
|
||||||
MemoryUsage usage = pool->get_memory_usage();
|
MemoryUsage usage = pool->get_memory_usage();
|
||||||
|
|
||||||
// Compare with GC usage threshold
|
if (allMemoryPoolsAffected || pool_always_affected_by_gc(i)) {
|
||||||
pool->set_last_collection_usage(usage);
|
// Compare with GC usage threshold
|
||||||
LowMemoryDetector::detect_after_gc_memory(pool);
|
pool->set_last_collection_usage(usage);
|
||||||
|
LowMemoryDetector::detect_after_gc_memory(pool);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,11 +45,12 @@ class GCMemoryManager;
|
|||||||
class OopClosure;
|
class OopClosure;
|
||||||
|
|
||||||
class MemoryManager : public CHeapObj<mtInternal> {
|
class MemoryManager : public CHeapObj<mtInternal> {
|
||||||
private:
|
protected:
|
||||||
enum {
|
enum {
|
||||||
max_num_pools = 10
|
max_num_pools = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
MemoryPool* _pools[max_num_pools];
|
MemoryPool* _pools[max_num_pools];
|
||||||
int _num_pools;
|
int _num_pools;
|
||||||
|
|
||||||
@ -67,7 +68,7 @@ public:
|
|||||||
return _pools[index];
|
return _pools[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_pool(MemoryPool* pool);
|
int add_pool(MemoryPool* pool);
|
||||||
|
|
||||||
bool is_manager(instanceHandle mh) { return oopDesc::equals(mh(), _memory_mgr_obj); }
|
bool is_manager(instanceHandle mh) { return oopDesc::equals(mh(), _memory_mgr_obj); }
|
||||||
|
|
||||||
@ -142,11 +143,21 @@ private:
|
|||||||
GCStatInfo* _current_gc_stat;
|
GCStatInfo* _current_gc_stat;
|
||||||
int _num_gc_threads;
|
int _num_gc_threads;
|
||||||
volatile bool _notification_enabled;
|
volatile bool _notification_enabled;
|
||||||
const char* _gc_end_message;
|
const char* _gc_end_message;
|
||||||
|
bool _pool_always_affected_by_gc[MemoryManager::max_num_pools];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GCMemoryManager(const char* name, const char* gc_end_message);
|
GCMemoryManager(const char* name, const char* gc_end_message);
|
||||||
~GCMemoryManager();
|
~GCMemoryManager();
|
||||||
|
|
||||||
|
void add_pool(MemoryPool* pool);
|
||||||
|
void add_pool(MemoryPool* pool, bool always_affected_by_gc);
|
||||||
|
|
||||||
|
bool pool_always_affected_by_gc(int index) {
|
||||||
|
assert(index >= 0 && index < num_memory_pools(), "Invalid index");
|
||||||
|
return _pool_always_affected_by_gc[index];
|
||||||
|
}
|
||||||
|
|
||||||
void initialize_gc_stat_info();
|
void initialize_gc_stat_info();
|
||||||
|
|
||||||
bool is_gc_memory_manager() { return true; }
|
bool is_gc_memory_manager() { return true; }
|
||||||
@ -158,7 +169,8 @@ public:
|
|||||||
void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
|
void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
|
||||||
bool recordAccumulatedGCTime);
|
bool recordAccumulatedGCTime);
|
||||||
void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime,
|
void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime,
|
||||||
bool recordGCEndTime, bool countCollection, GCCause::Cause cause);
|
bool recordGCEndTime, bool countCollection, GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected);
|
||||||
|
|
||||||
void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); }
|
void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); }
|
||||||
|
|
||||||
|
@ -182,10 +182,11 @@ void MemoryService::gc_begin(GCMemoryManager* manager, bool recordGCBeginTime,
|
|||||||
void MemoryService::gc_end(GCMemoryManager* manager, bool recordPostGCUsage,
|
void MemoryService::gc_end(GCMemoryManager* manager, bool recordPostGCUsage,
|
||||||
bool recordAccumulatedGCTime,
|
bool recordAccumulatedGCTime,
|
||||||
bool recordGCEndTime, bool countCollection,
|
bool recordGCEndTime, bool countCollection,
|
||||||
GCCause::Cause cause) {
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected) {
|
||||||
// register the GC end statistics and memory usage
|
// register the GC end statistics and memory usage
|
||||||
manager->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
|
manager->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
|
||||||
countCollection, cause);
|
countCollection, cause, allMemoryPoolsAffected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryService::oops_do(OopClosure* f) {
|
void MemoryService::oops_do(OopClosure* f) {
|
||||||
@ -232,6 +233,7 @@ Handle MemoryService::create_MemoryUsage_obj(MemoryUsage usage, TRAPS) {
|
|||||||
|
|
||||||
TraceMemoryManagerStats::TraceMemoryManagerStats(GCMemoryManager* gc_memory_manager,
|
TraceMemoryManagerStats::TraceMemoryManagerStats(GCMemoryManager* gc_memory_manager,
|
||||||
GCCause::Cause cause,
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected,
|
||||||
bool recordGCBeginTime,
|
bool recordGCBeginTime,
|
||||||
bool recordPreGCUsage,
|
bool recordPreGCUsage,
|
||||||
bool recordPeakUsage,
|
bool recordPeakUsage,
|
||||||
@ -239,7 +241,8 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(GCMemoryManager* gc_memory_mana
|
|||||||
bool recordAccumulatedGCTime,
|
bool recordAccumulatedGCTime,
|
||||||
bool recordGCEndTime,
|
bool recordGCEndTime,
|
||||||
bool countCollection) {
|
bool countCollection) {
|
||||||
initialize(gc_memory_manager, cause, recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
|
initialize(gc_memory_manager, cause, allMemoryPoolsAffected,
|
||||||
|
recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
|
||||||
recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
|
recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
|
||||||
countCollection);
|
countCollection);
|
||||||
}
|
}
|
||||||
@ -248,6 +251,7 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(GCMemoryManager* gc_memory_mana
|
|||||||
// the MemoryService
|
// the MemoryService
|
||||||
void TraceMemoryManagerStats::initialize(GCMemoryManager* gc_memory_manager,
|
void TraceMemoryManagerStats::initialize(GCMemoryManager* gc_memory_manager,
|
||||||
GCCause::Cause cause,
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected,
|
||||||
bool recordGCBeginTime,
|
bool recordGCBeginTime,
|
||||||
bool recordPreGCUsage,
|
bool recordPreGCUsage,
|
||||||
bool recordPeakUsage,
|
bool recordPeakUsage,
|
||||||
@ -256,6 +260,7 @@ void TraceMemoryManagerStats::initialize(GCMemoryManager* gc_memory_manager,
|
|||||||
bool recordGCEndTime,
|
bool recordGCEndTime,
|
||||||
bool countCollection) {
|
bool countCollection) {
|
||||||
_gc_memory_manager = gc_memory_manager;
|
_gc_memory_manager = gc_memory_manager;
|
||||||
|
_allMemoryPoolsAffected = allMemoryPoolsAffected;
|
||||||
_recordGCBeginTime = recordGCBeginTime;
|
_recordGCBeginTime = recordGCBeginTime;
|
||||||
_recordPreGCUsage = recordPreGCUsage;
|
_recordPreGCUsage = recordPreGCUsage;
|
||||||
_recordPeakUsage = recordPeakUsage;
|
_recordPeakUsage = recordPeakUsage;
|
||||||
@ -271,5 +276,5 @@ void TraceMemoryManagerStats::initialize(GCMemoryManager* gc_memory_manager,
|
|||||||
|
|
||||||
TraceMemoryManagerStats::~TraceMemoryManagerStats() {
|
TraceMemoryManagerStats::~TraceMemoryManagerStats() {
|
||||||
MemoryService::gc_end(_gc_memory_manager, _recordPostGCUsage, _recordAccumulatedGCTime,
|
MemoryService::gc_end(_gc_memory_manager, _recordPostGCUsage, _recordAccumulatedGCTime,
|
||||||
_recordGCEndTime, _countCollection, _cause);
|
_recordGCEndTime, _countCollection, _cause, _allMemoryPoolsAffected);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,8 @@ public:
|
|||||||
static void gc_end(GCMemoryManager* manager, bool recordPostGCUsage,
|
static void gc_end(GCMemoryManager* manager, bool recordPostGCUsage,
|
||||||
bool recordAccumulatedGCTime,
|
bool recordAccumulatedGCTime,
|
||||||
bool recordGCEndTime, bool countCollection,
|
bool recordGCEndTime, bool countCollection,
|
||||||
GCCause::Cause cause);
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected);
|
||||||
|
|
||||||
static void oops_do(OopClosure* f);
|
static void oops_do(OopClosure* f);
|
||||||
|
|
||||||
@ -116,6 +117,7 @@ public:
|
|||||||
class TraceMemoryManagerStats : public StackObj {
|
class TraceMemoryManagerStats : public StackObj {
|
||||||
private:
|
private:
|
||||||
GCMemoryManager* _gc_memory_manager;
|
GCMemoryManager* _gc_memory_manager;
|
||||||
|
bool _allMemoryPoolsAffected;
|
||||||
bool _recordGCBeginTime;
|
bool _recordGCBeginTime;
|
||||||
bool _recordPreGCUsage;
|
bool _recordPreGCUsage;
|
||||||
bool _recordPeakUsage;
|
bool _recordPeakUsage;
|
||||||
@ -128,6 +130,7 @@ public:
|
|||||||
TraceMemoryManagerStats() {}
|
TraceMemoryManagerStats() {}
|
||||||
TraceMemoryManagerStats(GCMemoryManager* gc_memory_manager,
|
TraceMemoryManagerStats(GCMemoryManager* gc_memory_manager,
|
||||||
GCCause::Cause cause,
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected = true,
|
||||||
bool recordGCBeginTime = true,
|
bool recordGCBeginTime = true,
|
||||||
bool recordPreGCUsage = true,
|
bool recordPreGCUsage = true,
|
||||||
bool recordPeakUsage = true,
|
bool recordPeakUsage = true,
|
||||||
@ -138,6 +141,7 @@ public:
|
|||||||
|
|
||||||
void initialize(GCMemoryManager* gc_memory_manager,
|
void initialize(GCMemoryManager* gc_memory_manager,
|
||||||
GCCause::Cause cause,
|
GCCause::Cause cause,
|
||||||
|
bool allMemoryPoolsAffected,
|
||||||
bool recordGCBeginTime,
|
bool recordGCBeginTime,
|
||||||
bool recordPreGCUsage,
|
bool recordPreGCUsage,
|
||||||
bool recordPeakUsage,
|
bool recordPeakUsage,
|
||||||
|
@ -86,7 +86,7 @@ public class TestMemoryMXBeansAndPoolsPresence {
|
|||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
switch (args[0]) {
|
switch (args[0]) {
|
||||||
case "G1":
|
case "G1":
|
||||||
test(new GCBeanDescription("G1 Young Generation", new String[] {"G1 Eden Space", "G1 Survivor Space"}),
|
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"}));
|
new GCBeanDescription("G1 Old Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"}));
|
||||||
break;
|
break;
|
||||||
case "CMS":
|
case "CMS":
|
||||||
|
221
test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java
Normal file
221
test/hotspot/jtreg/gc/g1/mixedgc/TestOldGenCollectionUsage.java
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 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
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test TestOldGenCollectionUsage.java
|
||||||
|
* @bug 8195115
|
||||||
|
* @summary G1 Old Gen's CollectionUsage.used is zero after mixed GC which is incorrect
|
||||||
|
* @key gc
|
||||||
|
* @requires vm.gc.G1
|
||||||
|
* @requires vm.opt.MaxGCPauseMillis == "null"
|
||||||
|
* @library /test/lib
|
||||||
|
* @modules java.base/jdk.internal.misc
|
||||||
|
* @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 -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;
|
||||||
|
import sun.hotspot.WhiteBox;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import java.lang.management.*;
|
||||||
|
|
||||||
|
// 8195115 says that for the "G1 Old Gen" MemoryPool, CollectionUsage.used
|
||||||
|
// is zero for G1 after a mixed collection, which is incorrect.
|
||||||
|
|
||||||
|
public class TestOldGenCollectionUsage {
|
||||||
|
|
||||||
|
private String poolName = "G1 Old Gen";
|
||||||
|
private String collectorName = "G1 Young Generation";
|
||||||
|
|
||||||
|
public static void main(String [] args) throws Exception {
|
||||||
|
TestOldGenCollectionUsage t = new TestOldGenCollectionUsage();
|
||||||
|
t.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestOldGenCollectionUsage() {
|
||||||
|
System.out.println("Monitor G1 Old Gen pool with G1 Young Generation collector.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
// Find memory pool and collector
|
||||||
|
List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
|
||||||
|
MemoryPoolMXBean pool = null;
|
||||||
|
boolean foundPool = false;
|
||||||
|
for (int i = 0; i < pools.size(); i++) {
|
||||||
|
pool = pools.get(i);
|
||||||
|
String name = pool.getName();
|
||||||
|
if (name.contains(poolName)) {
|
||||||
|
System.out.println("Found pool: " + name);
|
||||||
|
foundPool = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundPool) {
|
||||||
|
throw new RuntimeException(poolName + " not found, test with -XX:+UseG1GC");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
|
||||||
|
GarbageCollectorMXBean collector = null;
|
||||||
|
boolean foundCollector = false;
|
||||||
|
for (int i = 0; i < collectors.size(); i++) {
|
||||||
|
collector = collectors.get(i);
|
||||||
|
String name = collector.getName();
|
||||||
|
if (name.contains(collectorName)) {
|
||||||
|
System.out.println("Found collector: " + name);
|
||||||
|
foundCollector = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundCollector) {
|
||||||
|
throw new RuntimeException(collectorName + " not found, test with -XX:+UseG1GC");
|
||||||
|
}
|
||||||
|
|
||||||
|
MixedGCProvoker gcProvoker = new MixedGCProvoker();
|
||||||
|
gcProvoker.allocateOldObjects();
|
||||||
|
|
||||||
|
// Verify no non-zero result was stored
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
if (collectionTime <= 0) {
|
||||||
|
throw new RuntimeException("Collector has not run");
|
||||||
|
}
|
||||||
|
|
||||||
|
gcProvoker.provokeMixedGC();
|
||||||
|
|
||||||
|
usage = pool.getCollectionUsage().getUsed();
|
||||||
|
System.out.println(poolName + ": usage after GC = " + usage);
|
||||||
|
if (usage <= 0) {
|
||||||
|
throw new RuntimeException(poolName + " found with zero usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
long newCollectionCount = collector.getCollectionCount();
|
||||||
|
System.out.println(collectorName + ": collection count = "
|
||||||
|
+ newCollectionCount);
|
||||||
|
long newCollectionTime = collector.getCollectionTime();
|
||||||
|
System.out.println(collectorName + ": collection time = "
|
||||||
|
+ newCollectionTime);
|
||||||
|
if (newCollectionCount <= collectionCount) {
|
||||||
|
throw new RuntimeException("No new collection");
|
||||||
|
}
|
||||||
|
if (newCollectionTime <= collectionTime) {
|
||||||
|
throw new RuntimeException("Collector has not run some more");
|
||||||
|
}
|
||||||
|
|
||||||
|
System.out.println("Test passed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility class to guarantee a mixed GC. The class allocates several arrays and
|
||||||
|
* promotes them to the oldgen. After that it tries to provoke mixed GC by
|
||||||
|
* allocating new objects.
|
||||||
|
*
|
||||||
|
* The necessary condition for guaranteed mixed GC is running MixedGCProvoker is
|
||||||
|
* running in VM with the following flags: -XX:MaxTenuringThreshold=1 -Xms12M
|
||||||
|
* -Xmx12M -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0
|
||||||
|
* -XX:G1HeapRegionSize=1m
|
||||||
|
*/
|
||||||
|
public class MixedGCProvoker {
|
||||||
|
private final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||||
|
private final List<byte[]> liveOldObjects = new ArrayList<>();
|
||||||
|
private final List<byte[]> newObjects = new ArrayList<>();
|
||||||
|
|
||||||
|
public static final int ALLOCATION_SIZE = 20000;
|
||||||
|
public static final int ALLOCATION_COUNT = 15;
|
||||||
|
|
||||||
|
public void allocateOldObjects() {
|
||||||
|
List<byte[]> deadOldObjects = new ArrayList<>();
|
||||||
|
// Allocates buffer and promotes it to the old gen. Mix live and dead old
|
||||||
|
// objects
|
||||||
|
for (int i = 0; i < ALLOCATION_COUNT; ++i) {
|
||||||
|
liveOldObjects.add(new byte[ALLOCATION_SIZE * 5]);
|
||||||
|
deadOldObjects.add(new byte[ALLOCATION_SIZE * 5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do two young collections, MaxTenuringThreshold=1 will force promotion.
|
||||||
|
// G1HeapRegionSize=1m guarantees that old gen regions will be filled.
|
||||||
|
WB.youngGC();
|
||||||
|
WB.youngGC();
|
||||||
|
// Check it is promoted & keep alive
|
||||||
|
Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects),
|
||||||
|
"List of the objects is suppose to be in OldGen");
|
||||||
|
Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects),
|
||||||
|
"List of the objects is suppose to be in OldGen");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits until Concurent Mark Cycle finishes
|
||||||
|
* @param wb Whitebox instance
|
||||||
|
* @param sleepTime sleep time
|
||||||
|
*/
|
||||||
|
private void waitTillCMCFinished(int sleepTime) {
|
||||||
|
while (WB.g1InConcurrentMark()) {
|
||||||
|
if (sleepTime > -1) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(sleepTime);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void provokeMixedGC() {
|
||||||
|
waitTillCMCFinished(0);
|
||||||
|
WB.g1StartConcMarkCycle();
|
||||||
|
waitTillCMCFinished(0);
|
||||||
|
WB.youngGC();
|
||||||
|
|
||||||
|
System.out.println("Allocating new objects to provoke mixed GC");
|
||||||
|
// Provoke a mixed collection. G1MixedGCLiveThresholdPercent=100
|
||||||
|
// guarantees that full old gen regions will be included.
|
||||||
|
for (int i = 0; i < (ALLOCATION_COUNT * 20); i++) {
|
||||||
|
newObjects.add(new byte[ALLOCATION_SIZE]);
|
||||||
|
}
|
||||||
|
// check that liveOldObjects still alive
|
||||||
|
Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects),
|
||||||
|
"List of the objects is suppose to be in OldGen");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user