Mon, 28 Jan 2019 17:51:10 +0000
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
1.1 --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Tue Jan 08 04:55:25 2019 +0000 1.2 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Mon Jan 28 17:51:10 2019 +0000 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -9541,6 +9541,7 @@ 1.11 case CMSCollector::InitialMarking: 1.12 initialize(true /* fullGC */ , 1.13 cause /* cause of the GC */, 1.14 + true /* allMemoryPoolsAffected */, 1.15 true /* recordGCBeginTime */, 1.16 true /* recordPreGCUsage */, 1.17 false /* recordPeakUsage */, 1.18 @@ -9553,6 +9554,7 @@ 1.19 case CMSCollector::FinalMarking: 1.20 initialize(true /* fullGC */ , 1.21 cause /* cause of the GC */, 1.22 + true /* allMemoryPoolsAffected */, 1.23 false /* recordGCBeginTime */, 1.24 false /* recordPreGCUsage */, 1.25 false /* recordPeakUsage */, 1.26 @@ -9565,6 +9567,7 @@ 1.27 case CMSCollector::Sweeping: 1.28 initialize(true /* fullGC */ , 1.29 cause /* cause of the GC */, 1.30 + true /* allMemoryPoolsAffected */, 1.31 false /* recordGCBeginTime */, 1.32 false /* recordPreGCUsage */, 1.33 true /* recordPeakUsage */,
2.1 --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Jan 08 04:55:25 2019 +0000 2.2 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Jan 28 17:51:10 2019 +0000 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -4008,7 +4008,8 @@ 2.11 log_gc_header(); 2.12 2.13 TraceCollectorStats tcs(g1mm()->incremental_collection_counters()); 2.14 - TraceMemoryManagerStats tms(false /* fullGC */, gc_cause()); 2.15 + TraceMemoryManagerStats tms(false /* fullGC */, gc_cause(), 2.16 + yc_type() == Mixed /* allMemoryPoolsAffected */); 2.17 2.18 // If the secondary_free_list is not empty, append it to the 2.19 // free_list. No need to wait for the cleanup operation to finish;
3.1 --- a/src/share/vm/services/memoryManager.cpp Tue Jan 08 04:55:25 2019 +0000 3.2 +++ b/src/share/vm/services/memoryManager.cpp Mon Jan 28 17:51:10 2019 +0000 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -49,13 +49,15 @@ 3.11 (void)const_cast<instanceOop&>(_memory_mgr_obj = instanceOop(NULL)); 3.12 } 3.13 3.14 -void MemoryManager::add_pool(MemoryPool* pool) { 3.15 - assert(_num_pools < MemoryManager::max_num_pools, "_num_pools exceeds the max"); 3.16 - if (_num_pools < MemoryManager::max_num_pools) { 3.17 - _pools[_num_pools] = pool; 3.18 +int MemoryManager::add_pool(MemoryPool* pool) { 3.19 + int index = _num_pools; 3.20 + assert(index < MemoryManager::max_num_pools, "_num_pools exceeds the max"); 3.21 + if (index < MemoryManager::max_num_pools) { 3.22 + _pools[index] = pool; 3.23 _num_pools++; 3.24 } 3.25 pool->add_manager(this); 3.26 + return index; 3.27 } 3.28 3.29 MemoryManager* MemoryManager::get_code_cache_memory_manager() { 3.30 @@ -217,6 +219,15 @@ 3.31 delete _current_gc_stat; 3.32 } 3.33 3.34 +void GCMemoryManager::add_pool(MemoryPool* pool) { 3.35 + add_pool(pool, true); 3.36 +} 3.37 + 3.38 +void GCMemoryManager::add_pool(MemoryPool* pool, bool always_affected_by_gc) { 3.39 + int index = MemoryManager::add_pool(pool); 3.40 + _pool_always_affected_by_gc[index] = always_affected_by_gc; 3.41 +} 3.42 + 3.43 void GCMemoryManager::initialize_gc_stat_info() { 3.44 assert(MemoryService::num_memory_pools() > 0, "should have one or more memory pools"); 3.45 _last_gc_stat = new(ResourceObj::C_HEAP, mtGC) GCStatInfo(MemoryService::num_memory_pools()); 3.46 @@ -266,7 +277,8 @@ 3.47 void GCMemoryManager::gc_end(bool recordPostGCUsage, 3.48 bool recordAccumulatedGCTime, 3.49 bool recordGCEndTime, bool countCollection, 3.50 - GCCause::Cause cause) { 3.51 + GCCause::Cause cause, 3.52 + bool allMemoryPoolsAffected) { 3.53 if (recordAccumulatedGCTime) { 3.54 _accumulated_timer.stop(); 3.55 } 3.56 @@ -304,8 +316,11 @@ 3.57 MemoryUsage usage = pool->get_memory_usage(); 3.58 3.59 // Compare with GC usage threshold 3.60 - pool->set_last_collection_usage(usage); 3.61 - LowMemoryDetector::detect_after_gc_memory(pool); 3.62 + if (allMemoryPoolsAffected || pool_always_affected_by_gc(i)) { 3.63 + // Compare with GC usage threshold 3.64 + pool->set_last_collection_usage(usage); 3.65 + LowMemoryDetector::detect_after_gc_memory(pool); 3.66 + } 3.67 } 3.68 } 3.69
4.1 --- a/src/share/vm/services/memoryManager.hpp Tue Jan 08 04:55:25 2019 +0000 4.2 +++ b/src/share/vm/services/memoryManager.hpp Mon Jan 28 17:51:10 2019 +0000 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 4.6 + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. 4.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.8 * 4.9 * This code is free software; you can redistribute it and/or modify it 4.10 @@ -41,11 +41,12 @@ 4.11 class OopClosure; 4.12 4.13 class MemoryManager : public CHeapObj<mtInternal> { 4.14 -private: 4.15 +protected: 4.16 enum { 4.17 max_num_pools = 10 4.18 }; 4.19 4.20 +private: 4.21 MemoryPool* _pools[max_num_pools]; 4.22 int _num_pools; 4.23 4.24 @@ -75,7 +76,7 @@ 4.25 return _pools[index]; 4.26 } 4.27 4.28 - void add_pool(MemoryPool* pool); 4.29 + int add_pool(MemoryPool* pool); 4.30 4.31 bool is_manager(instanceHandle mh) { return mh() == _memory_mgr_obj; } 4.32 4.33 @@ -177,10 +178,20 @@ 4.34 GCStatInfo* _current_gc_stat; 4.35 int _num_gc_threads; 4.36 volatile bool _notification_enabled; 4.37 + bool _pool_always_affected_by_gc[MemoryManager::max_num_pools]; 4.38 + 4.39 public: 4.40 GCMemoryManager(); 4.41 ~GCMemoryManager(); 4.42 4.43 + void add_pool(MemoryPool* pool); 4.44 + void add_pool(MemoryPool* pool, bool always_affected_by_gc); 4.45 + 4.46 + bool pool_always_affected_by_gc(int index) { 4.47 + assert(index >= 0 && index < num_memory_pools(), "Invalid index"); 4.48 + return _pool_always_affected_by_gc[index]; 4.49 + } 4.50 + 4.51 void initialize_gc_stat_info(); 4.52 4.53 bool is_gc_memory_manager() { return true; } 4.54 @@ -192,7 +203,8 @@ 4.55 void gc_begin(bool recordGCBeginTime, bool recordPreGCUsage, 4.56 bool recordAccumulatedGCTime); 4.57 void gc_end(bool recordPostGCUsage, bool recordAccumulatedGCTime, 4.58 - bool recordGCEndTime, bool countCollection, GCCause::Cause cause); 4.59 + bool recordGCEndTime, bool countCollection, GCCause::Cause cause, 4.60 + bool allMemoryPoolsAffected); 4.61 4.62 void reset_gc_stat() { _num_collections = 0; _accumulated_timer.reset(); } 4.63
5.1 --- a/src/share/vm/services/memoryService.cpp Tue Jan 08 04:55:25 2019 +0000 5.2 +++ b/src/share/vm/services/memoryService.cpp Mon Jan 28 17:51:10 2019 +0000 5.3 @@ -1,5 +1,5 @@ 5.4 /* 5.5 - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 5.6 + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. 5.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.8 * 5.9 * This code is free software; you can redistribute it and/or modify it 5.10 @@ -187,7 +187,7 @@ 5.11 _managers_list->append(_major_gc_manager); 5.12 5.13 add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager); 5.14 - add_g1OldGen_memory_pool(g1h, _major_gc_manager); 5.15 + add_g1OldGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager); 5.16 } 5.17 #endif // INCLUDE_ALL_GCS 5.18 5.19 @@ -241,8 +241,8 @@ 5.20 5.21 // Add memory pool(s) for one generation 5.22 void MemoryService::add_generation_memory_pool(Generation* gen, 5.23 - MemoryManager* major_mgr, 5.24 - MemoryManager* minor_mgr) { 5.25 + GCMemoryManager* major_mgr, 5.26 + GCMemoryManager* minor_mgr) { 5.27 guarantee(gen != NULL, "No generation for memory pool"); 5.28 Generation::Name kind = gen->kind(); 5.29 int index = _pools_list->length(); 5.30 @@ -332,7 +332,9 @@ 5.31 5.32 5.33 #if INCLUDE_ALL_GCS 5.34 -void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, MemoryManager* major_mgr, MemoryManager* minor_mgr) { 5.35 +void MemoryService::add_psYoung_memory_pool(PSYoungGen* gen, 5.36 + GCMemoryManager* major_mgr, 5.37 + GCMemoryManager* minor_mgr) { 5.38 assert(major_mgr != NULL && minor_mgr != NULL, "Should have two managers"); 5.39 5.40 // Add a memory pool for each space and young gen doesn't 5.41 @@ -356,7 +358,7 @@ 5.42 _pools_list->append(survivor); 5.43 } 5.44 5.45 -void MemoryService::add_psOld_memory_pool(PSOldGen* gen, MemoryManager* mgr) { 5.46 +void MemoryService::add_psOld_memory_pool(PSOldGen* gen, GCMemoryManager* mgr) { 5.47 PSGenerationPool* old_gen = new PSGenerationPool(gen, 5.48 "PS Old Gen", 5.49 MemoryPool::Heap, 5.50 @@ -366,8 +368,8 @@ 5.51 } 5.52 5.53 void MemoryService::add_g1YoungGen_memory_pool(G1CollectedHeap* g1h, 5.54 - MemoryManager* major_mgr, 5.55 - MemoryManager* minor_mgr) { 5.56 + GCMemoryManager* major_mgr, 5.57 + GCMemoryManager* minor_mgr) { 5.58 assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers"); 5.59 5.60 G1EdenPool* eden = new G1EdenPool(g1h); 5.61 @@ -382,11 +384,13 @@ 5.62 } 5.63 5.64 void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h, 5.65 - MemoryManager* mgr) { 5.66 - assert(mgr != NULL, "should have one manager"); 5.67 + GCMemoryManager* major_mgr, 5.68 + GCMemoryManager* minor_mgr) { 5.69 + assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers"); 5.70 5.71 G1OldGenPool* old_gen = new G1OldGenPool(g1h); 5.72 - mgr->add_pool(old_gen); 5.73 + major_mgr->add_pool(old_gen); 5.74 + minor_mgr->add_pool(old_gen, false /* always_affected_by_gc */); 5.75 _pools_list->append(old_gen); 5.76 } 5.77 #endif // INCLUDE_ALL_GCS 5.78 @@ -484,7 +488,8 @@ 5.79 void MemoryService::gc_end(bool fullGC, bool recordPostGCUsage, 5.80 bool recordAccumulatedGCTime, 5.81 bool recordGCEndTime, bool countCollection, 5.82 - GCCause::Cause cause) { 5.83 + GCCause::Cause cause, 5.84 + bool allMemoryPoolsAffected) { 5.85 5.86 GCMemoryManager* mgr; 5.87 if (fullGC) { 5.88 @@ -496,7 +501,7 @@ 5.89 5.90 // register the GC end statistics and memory usage 5.91 mgr->gc_end(recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, 5.92 - countCollection, cause); 5.93 + countCollection, cause, allMemoryPoolsAffected); 5.94 } 5.95 5.96 void MemoryService::oops_do(OopClosure* f) { 5.97 @@ -573,10 +578,11 @@ 5.98 } 5.99 // this has to be called in a stop the world pause and represent 5.100 // an entire gc pause, start to finish: 5.101 - initialize(_fullGC, cause,true, true, true, true, true, true, true); 5.102 + initialize(_fullGC, cause, true, true, true, true, true, true, true, true); 5.103 } 5.104 TraceMemoryManagerStats::TraceMemoryManagerStats(bool fullGC, 5.105 GCCause::Cause cause, 5.106 + bool allMemoryPoolsAffected, 5.107 bool recordGCBeginTime, 5.108 bool recordPreGCUsage, 5.109 bool recordPeakUsage, 5.110 @@ -584,7 +590,8 @@ 5.111 bool recordAccumulatedGCTime, 5.112 bool recordGCEndTime, 5.113 bool countCollection) { 5.114 - initialize(fullGC, cause, recordGCBeginTime, recordPreGCUsage, recordPeakUsage, 5.115 + initialize(fullGC, cause, allMemoryPoolsAffected, 5.116 + recordGCBeginTime, recordPreGCUsage, recordPeakUsage, 5.117 recordPostGCUsage, recordAccumulatedGCTime, recordGCEndTime, 5.118 countCollection); 5.119 } 5.120 @@ -593,6 +600,7 @@ 5.121 // the MemoryService 5.122 void TraceMemoryManagerStats::initialize(bool fullGC, 5.123 GCCause::Cause cause, 5.124 + bool allMemoryPoolsAffected, 5.125 bool recordGCBeginTime, 5.126 bool recordPreGCUsage, 5.127 bool recordPeakUsage, 5.128 @@ -601,6 +609,7 @@ 5.129 bool recordGCEndTime, 5.130 bool countCollection) { 5.131 _fullGC = fullGC; 5.132 + _allMemoryPoolsAffected = allMemoryPoolsAffected; 5.133 _recordGCBeginTime = recordGCBeginTime; 5.134 _recordPreGCUsage = recordPreGCUsage; 5.135 _recordPeakUsage = recordPeakUsage; 5.136 @@ -616,5 +625,5 @@ 5.137 5.138 TraceMemoryManagerStats::~TraceMemoryManagerStats() { 5.139 MemoryService::gc_end(_fullGC, _recordPostGCUsage, _recordAccumulatedGCTime, 5.140 - _recordGCEndTime, _countCollection, _cause); 5.141 + _recordGCEndTime, _countCollection, _cause, _allMemoryPoolsAffected); 5.142 }
6.1 --- a/src/share/vm/services/memoryService.hpp Tue Jan 08 04:55:25 2019 +0000 6.2 +++ b/src/share/vm/services/memoryService.hpp Mon Jan 28 17:51:10 2019 +0000 6.3 @@ -1,5 +1,5 @@ 6.4 /* 6.5 - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 6.6 + * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. 6.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.8 * 6.9 * This code is free software; you can redistribute it and/or modify it 6.10 @@ -77,25 +77,26 @@ 6.11 static MemoryPool* _compressed_class_pool; 6.12 6.13 static void add_generation_memory_pool(Generation* gen, 6.14 - MemoryManager* major_mgr, 6.15 - MemoryManager* minor_mgr); 6.16 + GCMemoryManager* major_mgr, 6.17 + GCMemoryManager* minor_mgr); 6.18 static void add_generation_memory_pool(Generation* gen, 6.19 - MemoryManager* major_mgr) { 6.20 + GCMemoryManager* major_mgr) { 6.21 add_generation_memory_pool(gen, major_mgr, NULL); 6.22 } 6.23 6.24 6.25 static void add_psYoung_memory_pool(PSYoungGen* gen, 6.26 - MemoryManager* major_mgr, 6.27 - MemoryManager* minor_mgr); 6.28 + GCMemoryManager* major_mgr, 6.29 + GCMemoryManager* minor_mgr); 6.30 static void add_psOld_memory_pool(PSOldGen* gen, 6.31 - MemoryManager* mgr); 6.32 + GCMemoryManager* mgr); 6.33 6.34 static void add_g1YoungGen_memory_pool(G1CollectedHeap* g1h, 6.35 - MemoryManager* major_mgr, 6.36 - MemoryManager* minor_mgr); 6.37 + GCMemoryManager* major_mgr, 6.38 + GCMemoryManager* minor_mgr); 6.39 static void add_g1OldGen_memory_pool(G1CollectedHeap* g1h, 6.40 - MemoryManager* mgr); 6.41 + GCMemoryManager* major_mgr, 6.42 + GCMemoryManager* minor_mgr); 6.43 6.44 static MemoryPool* add_space(ContiguousSpace* space, 6.45 const char* name, 6.46 @@ -162,7 +163,8 @@ 6.47 static void gc_end(bool fullGC, bool recordPostGCUsage, 6.48 bool recordAccumulatedGCTime, 6.49 bool recordGCEndTime, bool countCollection, 6.50 - GCCause::Cause cause); 6.51 + GCCause::Cause cause, 6.52 + bool allMemoryPoolsAffected); 6.53 6.54 6.55 static void oops_do(OopClosure* f); 6.56 @@ -185,6 +187,7 @@ 6.57 class TraceMemoryManagerStats : public StackObj { 6.58 private: 6.59 bool _fullGC; 6.60 + bool _allMemoryPoolsAffected; 6.61 bool _recordGCBeginTime; 6.62 bool _recordPreGCUsage; 6.63 bool _recordPeakUsage; 6.64 @@ -197,6 +200,7 @@ 6.65 TraceMemoryManagerStats() {} 6.66 TraceMemoryManagerStats(bool fullGC, 6.67 GCCause::Cause cause, 6.68 + bool allMemoryPoolsAffected = true, 6.69 bool recordGCBeginTime = true, 6.70 bool recordPreGCUsage = true, 6.71 bool recordPeakUsage = true, 6.72 @@ -207,6 +211,7 @@ 6.73 6.74 void initialize(bool fullGC, 6.75 GCCause::Cause cause, 6.76 + bool allMemoryPoolsAffected, 6.77 bool recordGCBeginTime, 6.78 bool recordPreGCUsage, 6.79 bool recordPeakUsage,
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/test/gc/TestMemoryMXBeansAndPoolsPresence.java Mon Jan 28 17:51:10 2019 +0000 7.3 @@ -0,0 +1,101 @@ 7.4 +/* 7.5 + * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. 7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 7.7 + * 7.8 + * This code is free software; you can redistribute it and/or modify it 7.9 + * under the terms of the GNU General Public License version 2 only, as 7.10 + * published by the Free Software Foundation. 7.11 + * 7.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 7.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 7.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 7.15 + * version 2 for more details (a copy is included in the LICENSE file that 7.16 + * accompanied this code). 7.17 + * 7.18 + * You should have received a copy of the GNU General Public License version 7.19 + * 2 along with this work; if not, write to the Free Software Foundation, 7.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 7.21 + * 7.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 7.23 + * or visit www.oracle.com if you need additional information or have any 7.24 + * questions. 7.25 + */ 7.26 + 7.27 +/* @test TestMemoryMXBeansAndPoolsPresence 7.28 + * @key gc 7.29 + * @bug 8191564 7.30 + * @summary Tests that GarbageCollectorMXBeans and GC MemoryPools are created. 7.31 + * @library /testlibrary 7.32 + * @requires vm.gc == null 7.33 + * @run main/othervm -XX:+UseParallelGC TestMemoryMXBeansAndPoolsPresence Parallel 7.34 + * @run main/othervm -XX:+UseSerialGC TestMemoryMXBeansAndPoolsPresence Serial 7.35 + * @run main/othervm -XX:+UseConcMarkSweepGC TestMemoryMXBeansAndPoolsPresence CMS 7.36 + * @run main/othervm -XX:+UseG1GC TestMemoryMXBeansAndPoolsPresence G1 7.37 + */ 7.38 + 7.39 +import java.util.List; 7.40 +import java.util.ArrayList; 7.41 +import java.lang.management.*; 7.42 +import java.util.stream.*; 7.43 + 7.44 +import com.oracle.java.testlibrary.Asserts; 7.45 + 7.46 +class GCBeanDescription { 7.47 + public String name; 7.48 + public String[] poolNames; 7.49 + 7.50 + public GCBeanDescription(String name, String[] poolNames) { 7.51 + this.name = name; 7.52 + this.poolNames = poolNames; 7.53 + } 7.54 +} 7.55 + 7.56 +public class TestMemoryMXBeansAndPoolsPresence { 7.57 + public static void test(GCBeanDescription... expectedBeans) { 7.58 + List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans(); 7.59 + 7.60 + List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); 7.61 + Asserts.assertEQ(expectedBeans.length, gcBeans.size()); 7.62 + 7.63 + for (GCBeanDescription desc : expectedBeans) { 7.64 + List<GarbageCollectorMXBean> beans = gcBeans.stream() 7.65 + .filter(b -> b.getName().equals(desc.name)) 7.66 + .collect(Collectors.toList()); 7.67 + Asserts.assertEQ(beans.size(), 1); 7.68 + 7.69 + GarbageCollectorMXBean bean = beans.get(0); 7.70 + Asserts.assertEQ(desc.name, bean.getName()); 7.71 + 7.72 + String[] pools = bean.getMemoryPoolNames(); 7.73 + Asserts.assertEQ(desc.poolNames.length, pools.length); 7.74 + for (int i = 0; i < desc.poolNames.length; i++) { 7.75 + Asserts.assertEQ(desc.poolNames[i], pools[i]); 7.76 + } 7.77 + } 7.78 + } 7.79 + 7.80 + public static void main(String[] args) { 7.81 + switch (args[0]) { 7.82 + case "G1": 7.83 + test(new GCBeanDescription("G1 Young Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"}), 7.84 + new GCBeanDescription("G1 Old Generation", new String[] {"G1 Eden Space", "G1 Survivor Space", "G1 Old Gen"})); 7.85 + break; 7.86 + case "CMS": 7.87 + test(new GCBeanDescription("ParNew", new String[] {"Par Eden Space", "Par Survivor Space"}), 7.88 + new GCBeanDescription("ConcurrentMarkSweep", new String[] {"Par Eden Space", "Par Survivor Space", "CMS Old Gen"})); 7.89 + break; 7.90 + case "Parallel": 7.91 + test(new GCBeanDescription("PS Scavenge", new String[] {"PS Eden Space", "PS Survivor Space"}), 7.92 + new GCBeanDescription("PS MarkSweep", new String[] {"PS Eden Space", "PS Survivor Space", "PS Old Gen"})); 7.93 + break; 7.94 + case "Serial": 7.95 + test(new GCBeanDescription("Copy", new String[] {"Eden Space", "Survivor Space"}), 7.96 + new GCBeanDescription("MarkSweepCompact", new String[] {"Eden Space", "Survivor Space", "Tenured Gen"})); 7.97 + break; 7.98 + default: 7.99 + Asserts.assertTrue(false); 7.100 + break; 7.101 + 7.102 + } 7.103 + } 7.104 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/test/gc/g1/mixedgc/TestOldGenCollectionUsage.java Mon Jan 28 17:51:10 2019 +0000 8.3 @@ -0,0 +1,232 @@ 8.4 +/* 8.5 + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. 8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 8.7 + * 8.8 + * This code is free software; you can redistribute it and/or modify it 8.9 + * under the terms of the GNU General Public License version 2 only, as 8.10 + * published by the Free Software Foundation. 8.11 + * 8.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 8.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 8.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 8.15 + * version 2 for more details (a copy is included in the LICENSE file that 8.16 + * accompanied this code). 8.17 + * 8.18 + * You should have received a copy of the GNU General Public License version 8.19 + * 2 along with this work; if not, write to the Free Software Foundation, 8.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 8.21 + * 8.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 8.23 + * or visit www.oracle.com if you need additional information or have any 8.24 + * questions. 8.25 + */ 8.26 + 8.27 +/* 8.28 + * @test TestOldGenCollectionUsage.java 8.29 + * @bug 8195115 8.30 + * @summary G1 Old Gen's CollectionUsage.used is zero after mixed GC which is incorrect 8.31 + * @key gc 8.32 + * @requires vm.gc=="G1" | vm.gc=="null" 8.33 + * @requires vm.opt.MaxGCPauseMillis == "null" 8.34 + * @library /testlibrary /testlibrary/whitebox 8.35 + * @build ClassFileInstaller com.oracle.java.testlibrary.* sun.hotspot.WhiteBox TestOldGenCollectionUsage 8.36 + * @run main ClassFileInstaller sun.hotspot.WhiteBox 8.37 + * sun.hotspot.WhiteBox$WhiteBoxPermission 8.38 + * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions 8.39 + * -XX:+WhiteBoxAPI -verbose:gc -XX:SurvivorRatio=1 -Xmx14m -Xms14m -XX:MaxTenuringThreshold=1 8.40 + * -XX:InitiatingHeapOccupancyPercent=100 -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 8.41 + * -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 8.42 + * TestOldGenCollectionUsage 8.43 + */ 8.44 + 8.45 +import com.oracle.java.testlibrary.Asserts; 8.46 +import sun.hotspot.WhiteBox; 8.47 + 8.48 +import java.util.ArrayList; 8.49 +import java.util.List; 8.50 +import java.util.Collections; 8.51 + 8.52 +import java.lang.management.*; 8.53 + 8.54 +// 8195115 says that for the "G1 Old Gen" MemoryPool, CollectionUsage.used 8.55 +// is zero for G1 after a mixed collection, which is incorrect. 8.56 + 8.57 +public class TestOldGenCollectionUsage { 8.58 + 8.59 + private String poolName = "G1 Old Gen"; 8.60 + private String collectorName = "G1 Young Generation"; 8.61 + 8.62 + public static void main(String [] args) throws Exception { 8.63 + TestOldGenCollectionUsage t = new TestOldGenCollectionUsage(); 8.64 + t.run(); 8.65 + } 8.66 + 8.67 + public TestOldGenCollectionUsage() { 8.68 + System.out.println("Monitor G1 Old Gen pool with G1 Young Generation collector."); 8.69 + } 8.70 + 8.71 + public void run() { 8.72 + // Find memory pool and collector 8.73 + List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); 8.74 + MemoryPoolMXBean pool = null; 8.75 + boolean foundPool = false; 8.76 + for (int i = 0; i < pools.size(); i++) { 8.77 + pool = pools.get(i); 8.78 + String name = pool.getName(); 8.79 + if (name.contains(poolName)) { 8.80 + System.out.println("Found pool: " + name); 8.81 + foundPool = true; 8.82 + break; 8.83 + } 8.84 + } 8.85 + if (!foundPool) { 8.86 + throw new RuntimeException(poolName + " not found, test with -XX:+UseG1GC"); 8.87 + } 8.88 + 8.89 + List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans(); 8.90 + GarbageCollectorMXBean collector = null; 8.91 + boolean foundCollector = false; 8.92 + for (int i = 0; i < collectors.size(); i++) { 8.93 + collector = collectors.get(i); 8.94 + String name = collector.getName(); 8.95 + if (name.contains(collectorName)) { 8.96 + System.out.println("Found collector: " + name); 8.97 + foundCollector = true; 8.98 + break; 8.99 + } 8.100 + } 8.101 + if (!foundCollector) { 8.102 + throw new RuntimeException(collectorName + " not found, test with -XX:+UseG1GC"); 8.103 + } 8.104 + 8.105 + MixedGCProvoker gcProvoker = new MixedGCProvoker(); 8.106 + gcProvoker.allocateOldObjects(); 8.107 + 8.108 + // Verify no non-zero result was stored 8.109 + long usage = pool.getCollectionUsage().getUsed(); 8.110 + System.out.println(poolName + ": usage after GC = " + usage); 8.111 + if (usage > 0) { 8.112 + throw new RuntimeException("Premature mixed collections(s)"); 8.113 + } 8.114 + 8.115 + // Verify that collections were done 8.116 + long collectionCount = collector.getCollectionCount(); 8.117 + System.out.println(collectorName + ": collection count = " 8.118 + + collectionCount); 8.119 + long collectionTime = collector.getCollectionTime(); 8.120 + System.out.println(collectorName + ": collection time = " 8.121 + + collectionTime); 8.122 + if (collectionCount <= 0) { 8.123 + throw new RuntimeException("Collection count <= 0"); 8.124 + } 8.125 + if (collectionTime <= 0) { 8.126 + throw new RuntimeException("Collector has not run"); 8.127 + } 8.128 + 8.129 + gcProvoker.provokeMixedGC(); 8.130 + 8.131 + usage = pool.getCollectionUsage().getUsed(); 8.132 + System.out.println(poolName + ": usage after GC = " + usage); 8.133 + if (usage <= 0) { 8.134 + throw new RuntimeException(poolName + " found with zero usage"); 8.135 + } 8.136 + 8.137 + long newCollectionCount = collector.getCollectionCount(); 8.138 + System.out.println(collectorName + ": collection count = " 8.139 + + newCollectionCount); 8.140 + long newCollectionTime = collector.getCollectionTime(); 8.141 + System.out.println(collectorName + ": collection time = " 8.142 + + newCollectionTime); 8.143 + if (newCollectionCount <= collectionCount) { 8.144 + throw new RuntimeException("No new collection"); 8.145 + } 8.146 + if (newCollectionTime <= collectionTime) { 8.147 + throw new RuntimeException("Collector has not run some more"); 8.148 + } 8.149 + 8.150 + System.out.println("Test passed."); 8.151 + } 8.152 + 8.153 + /** 8.154 + * Utility class to guarantee a mixed GC. The class allocates several arrays and 8.155 + * promotes them to the oldgen. After that it tries to provoke mixed GC by 8.156 + * allocating new objects. 8.157 + * 8.158 + * The necessary condition for guaranteed mixed GC is running MixedGCProvoker is 8.159 + * running in VM with the following flags: -XX:MaxTenuringThreshold=1 -Xms12M 8.160 + * -Xmx12M -XX:G1MixedGCLiveThresholdPercent=100 -XX:G1HeapWastePercent=0 8.161 + * -XX:G1HeapRegionSize=1m 8.162 + */ 8.163 + public class MixedGCProvoker { 8.164 + private final WhiteBox WB = WhiteBox.getWhiteBox(); 8.165 + private final List<byte[]> liveOldObjects = new ArrayList<>(); 8.166 + private final List<byte[]> newObjects = new ArrayList<>(); 8.167 + 8.168 + public static final int ALLOCATION_SIZE = 20000; 8.169 + public static final int ALLOCATION_COUNT = 15; 8.170 + 8.171 + public void allocateOldObjects() { 8.172 + List<byte[]> deadOldObjects = new ArrayList<>(); 8.173 + // Allocates buffer and promotes it to the old gen. Mix live and dead old 8.174 + // objects 8.175 + for (int i = 0; i < ALLOCATION_COUNT; ++i) { 8.176 + liveOldObjects.add(new byte[ALLOCATION_SIZE * 5]); 8.177 + deadOldObjects.add(new byte[ALLOCATION_SIZE * 5]); 8.178 + } 8.179 + 8.180 + // Do two young collections, MaxTenuringThreshold=1 will force promotion. 8.181 + // G1HeapRegionSize=1m guarantees that old gen regions will be filled. 8.182 + WB.youngGC(); 8.183 + WB.youngGC(); 8.184 + // Check it is promoted & keep alive 8.185 + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), 8.186 + "List of the objects is suppose to be in OldGen"); 8.187 + Asserts.assertTrue(WB.isObjectInOldGen(deadOldObjects), 8.188 + "List of the objects is suppose to be in OldGen"); 8.189 + } 8.190 + 8.191 + /** 8.192 + * Waits until Concurent Mark Cycle finishes 8.193 + * @param wb Whitebox instance 8.194 + * @param sleepTime sleep time 8.195 + */ 8.196 + private void waitTillCMCFinished(int sleepTime) { 8.197 + while (WB.g1InConcurrentMark()) { 8.198 + if (sleepTime > -1) { 8.199 + try { 8.200 + Thread.sleep(sleepTime); 8.201 + } catch (InterruptedException e) { 8.202 + System.out.println("Got InterruptedException while waiting for ConcMarkCycle to finish"); 8.203 + } 8.204 + } 8.205 + } 8.206 + } 8.207 + 8.208 + public void provokeMixedGC() { 8.209 + waitTillCMCFinished(0); 8.210 + WB.g1StartConcMarkCycle(); 8.211 + waitTillCMCFinished(0); 8.212 + WB.youngGC(); 8.213 + 8.214 + System.out.println("Allocating new objects to provoke mixed GC"); 8.215 + // Provoke a mixed collection. G1MixedGCLiveThresholdPercent=100 8.216 + // guarantees that full old gen regions will be included. 8.217 + for (int i = 0; i < (ALLOCATION_COUNT * 20); i++) { 8.218 + try { 8.219 + newObjects.add(new byte[ALLOCATION_SIZE]); 8.220 + } catch (OutOfMemoryError e) { 8.221 + newObjects.clear(); 8.222 + WB.youngGC(); 8.223 + WB.youngGC(); 8.224 + System.out.println("OutOfMemoryError is reported, stop allocating new objects"); 8.225 + break; 8.226 + } 8.227 + } 8.228 + // check that liveOldObjects still alive 8.229 + Asserts.assertTrue(WB.isObjectInOldGen(liveOldObjects), 8.230 + "List of the objects is suppose to be in OldGen"); 8.231 + } 8.232 + 8.233 + } 8.234 + 8.235 +}