提交 65673b13 编写于 作者: P phh

8215934: G1 Old Gen MemoryPool CollectionUsage.used values don't reflect mixed GC results

Summary: Memory pools can now be optional collection participants, e.g., G1 Old Gen in an incremental collection.
Reviewed-by: tschatzl, jcbeyler, andrew
上级 d18efe73
/*
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, 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
......@@ -9541,6 +9541,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
case CMSCollector::InitialMarking:
initialize(true /* fullGC */ ,
cause /* cause of the GC */,
true /* allMemoryPoolsAffected */,
true /* recordGCBeginTime */,
true /* recordPreGCUsage */,
false /* recordPeakUsage */,
......@@ -9553,6 +9554,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
case CMSCollector::FinalMarking:
initialize(true /* fullGC */ ,
cause /* cause of the GC */,
true /* allMemoryPoolsAffected */,
false /* recordGCBeginTime */,
false /* recordPreGCUsage */,
false /* recordPeakUsage */,
......@@ -9565,6 +9567,7 @@ TraceCMSMemoryManagerStats::TraceCMSMemoryManagerStats(CMSCollector::CollectorSt
case CMSCollector::Sweeping:
initialize(true /* fullGC */ ,
cause /* cause of the GC */,
true /* allMemoryPoolsAffected */,
false /* recordGCBeginTime */,
false /* recordPreGCUsage */,
true /* recordPeakUsage */,
......
/*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2019, 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
......@@ -4008,7 +4008,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
log_gc_header();
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
TraceMemoryManagerStats tms(false /* fullGC */, gc_cause());
TraceMemoryManagerStats tms(false /* fullGC */, gc_cause(),
yc_type() == Mixed /* allMemoryPoolsAffected */);
// If the secondary_free_list is not empty, append it to the
// free_list. No need to wait for the cleanup operation to finish;
......
/*
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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,13 +49,15 @@ MemoryManager::MemoryManager() {
(void)const_cast<instanceOop&>(_memory_mgr_obj = instanceOop(NULL));
}
void MemoryManager::add_pool(MemoryPool* pool) {
assert(_num_pools < MemoryManager::max_num_pools, "_num_pools exceeds the max");
if (_num_pools < MemoryManager::max_num_pools) {
_pools[_num_pools] = pool;
int MemoryManager::add_pool(MemoryPool* pool) {
int index = _num_pools;
assert(index < MemoryManager::max_num_pools, "_num_pools exceeds the max");
if (index < MemoryManager::max_num_pools) {
_pools[index] = pool;
_num_pools++;
}
pool->add_manager(this);
return index;
}
MemoryManager* MemoryManager::get_code_cache_memory_manager() {
......@@ -217,6 +219,15 @@ GCMemoryManager::~GCMemoryManager() {
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() {
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());
......@@ -266,7 +277,8 @@ void GCMemoryManager::gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
void GCMemoryManager::gc_end(bool recordPostGCUsage,
bool recordAccumulatedGCTime,
bool recordGCEndTime, bool countCollection,
GCCause::Cause cause) {
GCCause::Cause cause,
bool allMemoryPoolsAffected) {
if (recordAccumulatedGCTime) {
_accumulated_timer.stop();
}
......@@ -303,11 +315,14 @@ void GCMemoryManager::gc_end(bool recordPostGCUsage,
MemoryPool* pool = get_memory_pool(i);
MemoryUsage usage = pool->get_memory_usage();
// Compare with GC usage threshold
if (allMemoryPoolsAffected || pool_always_affected_by_gc(i)) {
// Compare with GC usage threshold
pool->set_last_collection_usage(usage);
LowMemoryDetector::detect_after_gc_memory(pool);
}
}
}
if (countCollection) {
_num_collections++;
......
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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
......@@ -41,11 +41,12 @@ class GCMemoryManager;
class OopClosure;
class MemoryManager : public CHeapObj<mtInternal> {
private:
protected:
enum {
max_num_pools = 10
};
private:
MemoryPool* _pools[max_num_pools];
int _num_pools;
......@@ -75,7 +76,7 @@ public:
return _pools[index];
}
void add_pool(MemoryPool* pool);
int add_pool(MemoryPool* pool);
bool is_manager(instanceHandle mh) { return mh() == _memory_mgr_obj; }
......@@ -177,10 +178,20 @@ private:
GCStatInfo* _current_gc_stat;
int _num_gc_threads;
volatile bool _notification_enabled;
bool _pool_always_affected_by_gc[MemoryManager::max_num_pools];
public:
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();
bool is_gc_memory_manager() { return true; }
......@@ -192,7 +203,8 @@ public:
void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage,
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(); }
......
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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
......@@ -187,7 +187,7 @@ void MemoryService::add_g1_heap_info(G1CollectedHeap* g1h) {
_managers_list->append(_major_gc_manager);
add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager);
add_g1OldGen_memory_pool(g1h, _major_gc_manager);
add_g1OldGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager);
}
#endif // INCLUDE_ALL_GCS
......@@ -241,8 +241,8 @@ MemoryPool* MemoryService::add_cms_space(CompactibleFreeListSpace* space,
// Add memory pool(s) for one generation
void MemoryService::add_generation_memory_pool(Generation* gen,
MemoryManager* major_mgr,
MemoryManager* minor_mgr) {
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr) {
guarantee(gen != NULL, "No generation for memory pool");
Generation::Name kind = gen->kind();
int index = _pools_list->length();
......@@ -332,7 +332,9 @@ void MemoryService::add_generation_memory_pool(Generation* gen,
#if INCLUDE_ALL_GCS
void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) {
void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen,
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr) {
assert(major_mgr != NULL && minor_mgr != NULL, "Should have two managers");
// Add a memory pool for each space and young gen doesn't
......@@ -356,7 +358,7 @@ void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, MemoryManager* majo
_pools_list->append(survivor);
}
void MemoryService::add_psOld_memory_pool(PSOldGen* gen, MemoryManager* mgr) {
void MemoryService::add_psOld_memory_pool(PSOldGen* gen, GCMemoryManager* mgr) {
PSGenerationPool* old_gen = new PSGenerationPool(gen,
"PS Old Gen",
MemoryPool::Heap,
......@@ -366,8 +368,8 @@ void MemoryService::add_psOld_memory_pool(PSOldGen* gen, MemoryManager* mgr) {
}
void MemoryService::add_g1YoungGen_memory_pool(G1CollectedHeap* g1h,
MemoryManager* major_mgr,
MemoryManager* minor_mgr) {
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr) {
assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers");
G1EdenPool* eden = new G1EdenPool(g1h);
......@@ -382,11 +384,13 @@ void MemoryService::add_g1YoungGen_memory_pool(G1CollectedHeap* g1h,
}
void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h,
MemoryManager* mgr) {
assert(mgr != NULL, "should have one manager");
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr) {
assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers");
G1OldGenPool* old_gen = new G1OldGenPool(g1h);
mgr->add_pool(old_gen);
major_mgr->add_pool(old_gen);
minor_mgr->add_pool(old_gen, false /* always_affected_by_gc */);
_pools_list->append(old_gen);
}
#endif // INCLUDE_ALL_GCS
......@@ -484,7 +488,8 @@ void MemoryService::gc_begin(bool fullGC, bool recordGCBeginTime,
void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage,
bool recordAccumulatedGCTime,
bool recordGCEndTime, bool countCollection,
GCCause::Cause cause) {
GCCause::Cause cause,
bool allMemoryPoolsAffected) {
GCMemoryManager* mgr;
if (fullGC) {
......@@ -496,7 +501,7 @@ void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage,
// register the GC end statistics and memory usage
mgr->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
countCollection, cause);
countCollection, cause, allMemoryPoolsAffected);
}
void MemoryService::oops_do(OopClosure* f) {
......@@ -573,10 +578,11 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(Generation::Name kind, GCCause:
}
// this has to be called in a stop the world pause and represent
// an entire gc pause, start to finish:
initialize(_fullGC, cause,true, true, true, true, true, true, true);
initialize(_fullGC, cause, true, true, true, true, true, true, true, true);
}
TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC,
GCCause::Cause cause,
bool allMemoryPoolsAffected,
bool recordGCBeginTime,
bool recordPreGCUsage,
bool recordPeakUsage,
......@@ -584,7 +590,8 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC,
bool recordAccumulatedGCTime,
bool recordGCEndTime,
bool countCollection) {
initialize(fullGC, cause, recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
initialize(fullGC, cause, allMemoryPoolsAffected,
recordGCBeginTime, recordPreGCUsage, recordPeakUsage,
recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime,
countCollection);
}
......@@ -593,6 +600,7 @@ TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC,
// the MemoryService
void TraceMemoryManagerStats::initialize(bool fullGC,
GCCause::Cause cause,
bool allMemoryPoolsAffected,
bool recordGCBeginTime,
bool recordPreGCUsage,
bool recordPeakUsage,
......@@ -601,6 +609,7 @@ void TraceMemoryManagerStats::initialize(bool fullGC,
bool recordGCEndTime,
bool countCollection) {
_fullGC = fullGC;
_allMemoryPoolsAffected = allMemoryPoolsAffected;
_recordGCBeginTime = recordGCBeginTime;
_recordPreGCUsage = recordPreGCUsage;
_recordPeakUsage = recordPeakUsage;
......@@ -616,5 +625,5 @@ void TraceMemoryManagerStats::initialize(bool fullGC,
TraceMemoryManagerStats::~TraceMemoryManagerStats() {
MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime,
_recordGCEndTime, _countCollection, _cause);
_recordGCEndTime, _countCollection, _cause, _allMemoryPoolsAffected);
}
/*
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2019, 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
......@@ -77,25 +77,26 @@ private:
static MemoryPool* _compressed_class_pool;
static void add_generation_memory_pool(Generation* gen,
MemoryManager* major_mgr,
MemoryManager* minor_mgr);
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr);
static void add_generation_memory_pool(Generation* gen,
MemoryManager* major_mgr) {
GCMemoryManager* major_mgr) {
add_generation_memory_pool(gen, major_mgr, NULL);
}
static void add_psYoung_memory_pool(PSYoungGen* gen,
MemoryManager* major_mgr,
MemoryManager* minor_mgr);
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr);
static void add_psOld_memory_pool(PSOldGen* gen,
MemoryManager* mgr);
GCMemoryManager* mgr);
static void add_g1YoungGen_memory_pool(G1CollectedHeap* g1h,
MemoryManager* major_mgr,
MemoryManager* minor_mgr);
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr);
static void add_g1OldGen_memory_pool(G1CollectedHeap* g1h,
MemoryManager* mgr);
GCMemoryManager* major_mgr,
GCMemoryManager* minor_mgr);
static MemoryPool* add_space(ContiguousSpace* space,
const char* name,
......@@ -162,7 +163,8 @@ public:
static void gc_end(bool fullGC, bool recordPostGCUsage,
bool recordAccumulatedGCTime,
bool recordGCEndTime, bool countCollection,
GCCause::Cause cause);
GCCause::Cause cause,
bool allMemoryPoolsAffected);
static void oops_do(OopClosure* f);
......@@ -185,6 +187,7 @@ public:
class TraceMemoryManagerStats : public StackObj {
private:
bool _fullGC;
bool _allMemoryPoolsAffected;
bool _recordGCBeginTime;
bool _recordPreGCUsage;
bool _recordPeakUsage;
......@@ -197,6 +200,7 @@ public:
TraceMemoryManagerStats() {}
TraceMemoryManagerStats(bool fullGC,
GCCause::Cause cause,
bool allMemoryPoolsAffected = true,
bool recordGCBeginTime = true,
bool recordPreGCUsage = true,
bool recordPeakUsage = true,
......@@ -207,6 +211,7 @@ public:
void initialize(bool fullGC,
GCCause::Cause cause,
bool allMemoryPoolsAffected,
bool recordGCBeginTime,
bool recordPreGCUsage,
bool recordPeakUsage,
......
/*
* Copyright (c) 2017, 2019, 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 TestMemoryMXBeansAndPoolsPresence
* @key gc
* @bug 8191564
* @summary Tests that GarbageCollectorMXBeans and GC MemoryPools are created.
* @library /testlibrary
* @requires vm.gc == null
* @run main/othervm -XX:+UseParallelGC TestMemoryMXBeansAndPoolsPresence Parallel
* @run main/othervm -XX:+UseSerialGC TestMemoryMXBeansAndPoolsPresence Serial
* @run main/othervm -XX:+UseConcMarkSweepGC TestMemoryMXBeansAndPoolsPresence CMS
* @run main/othervm -XX:+UseG1GC TestMemoryMXBeansAndPoolsPresence G1
*/
import java.util.List;
import java.util.ArrayList;
import java.lang.management.*;
import java.util.stream.*;
import com.oracle.java.testlibrary.Asserts;
class GCBeanDescription {
public String name;
public String[] poolNames;
public GCBeanDescription(String name, String[] poolNames) {
this.name = name;
this.poolNames = poolNames;
}
}
public class TestMemoryMXBeansAndPoolsPresence {
public static void test(GCBeanDescription... expectedBeans) {
List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
Asserts.assertEQ(expectedBeans.length, gcBeans.size());
for (GCBeanDescription desc : expectedBeans) {
List<GarbageCollectorMXBean> beans = gcBeans.stream()
.filter(b -> b.getName().equals(desc.name))
.collect(Collectors.toList());
Asserts.assertEQ(beans.size(), 1);
GarbageCollectorMXBean bean = beans.get(0);
Asserts.assertEQ(desc.name, bean.getName());
String[] pools = bean.getMemoryPoolNames();
Asserts.assertEQ(desc.poolNames.length, pools.length);
for (int i = 0; i < desc.poolNames.length; i++) {
Asserts.assertEQ(desc.poolNames[i], pools[i]);
}
}
}
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"}));
break;
case "CMS":
test(new GCBeanDescription("ParNew", new String[] {"Par Eden Space", "Par Survivor Space"}),
new GCBeanDescription("ConcurrentMarkSweep", new String[] {"Par Eden Space", "Par Survivor Space", "CMS Old Gen"}));
break;
case "Parallel":
test(new GCBeanDescription("PS Scavenge", new String[] {"PS Eden Space", "PS Survivor Space"}),
new GCBeanDescription("PS MarkSweep", new String[] {"PS Eden Space", "PS Survivor Space", "PS Old Gen"}));
break;
case "Serial":
test(new GCBeanDescription("Copy", new String[] {"Eden Space", "Survivor Space"}),
new GCBeanDescription("MarkSweepCompact", new String[] {"Eden Space", "Survivor Space", "Tenured Gen"}));
break;
default:
Asserts.assertTrue(false);
break;
}
}
}
/*
* Copyright (c) 2018, 2019, 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" | vm.gc=="null"
* @requires vm.opt.MaxGCPauseMillis == "null"
* @library /testlibrary /testlibrary/whitebox
* @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.WhiteBox TestOldGenCollectionUsage
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @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:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000
* -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100
* TestOldGenCollectionUsage
*/
import com.oracle.java.testlibrary.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++) {
try {
newObjects.add(new byte[ALLOCATION_SIZE]);
} catch (OutOfMemoryError e) {
newObjects.clear();
WB.youngGC();
WB.youngGC();
System.out.println("OutOfMemoryError is reported, stop allocating new objects");
break;
}
}
// check that liveOldObjects still alive
Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects),
"List of the objects is suppose to be in OldGen");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册