1 /* 2 * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test TestMixedOldGenCollectionUsage.java 26 * @bug 8195115 27 * @requires vm.gc.G1 28 * @summary G1 Old Gen's CollectionUsage.used is zero after mixed GC which is incorrect 29 * @run main/othervm -Xmx64m -Xms64m -verbose:gc -XX:+UseG1GC TestMixedOldGenCollectionUsage 30 */ 31 import java.util.*; 32 import java.lang.management.*; 33 34 // 8195115 says that for the "G1 Old Gen" MemoryPool, CollectionUsage.used 35 // is zero for G1 after a mixed collection. 36 37 public class TestMixedOldGenCollectionUsage { 38 39 private String poolName = "G1 Old Gen"; 40 private String collectorName = "G1 Young Generation"; 41 42 public static void main(String [] args) { 43 TestMixedOldGenCollectionUsage t = new TestMixedOldGenCollectionUsage(); 44 t.run(); 45 } 46 47 public TestMixedOldGenCollectionUsage() { 48 System.out.println("Monitor G1 Old Gen pool with G1 Young Generation collector."); 49 } 50 51 public void run() { 52 // Find memory pool and collector 53 List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); 54 MemoryPoolMXBean pool = null; 55 boolean foundPool = false; 56 for (int i = 0; i < pools.size(); i++) { 57 pool = pools.get(i); 58 String name = pool.getName(); 59 if (name.contains(poolName)) { 60 System.out.println("Found pool: " + name); 61 foundPool = true; 62 break; 63 } 64 } 65 if (!foundPool) { 66 throw new RuntimeException(poolName + " not found, test with -XX:+UseG1GC"); 67 } 68 69 List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans(); 70 GarbageCollectorMXBean collector = null; 71 boolean foundCollector = false; 72 for (int i = 0; i < collectors.size(); i++) { 73 collector = collectors.get(i); 74 String name = collector.getName(); 75 if (name.contains(collectorName)) { 76 System.out.println("Found collector: " + name); 77 foundCollector = true; 78 break; 79 } 80 } 81 if (!foundCollector) { 82 throw new RuntimeException(collectorName + " not found, test with -XX:+UseG1GC"); 83 } 84 85 // Use some memory, enough that young, but not mixed, collections 86 // have happened. 87 allocationWork(20*1024*1024, 0); 88 System.out.println("Done allocationWork for pure young collections"); 89 90 // Verify no non-zero result was stored 91 long usage = pool.getCollectionUsage().getUsed(); 92 System.out.println(poolName + ": usage after GC = " + usage); 93 if (usage > 0) { 94 throw new RuntimeException("Premature mixed collections(s)"); 95 } 96 97 // Verify that collections were done 98 long collectionCount = collector.getCollectionCount(); 99 System.out.println(collectorName + ": collection count = " 100 + collectionCount); 101 long collectionTime = collector.getCollectionTime(); 102 System.out.println(collectorName + ": collection time = " 103 + collectionTime); 104 if (collectionCount <= 0) { 105 throw new RuntimeException("Collection count <= 0"); 106 } 107 if (collectionTime <= 0) { 108 throw new RuntimeException("Collector has not run"); 109 } 110 111 // Must run with options to ensure no stop the world full GC, 112 // but at least one GC cycle that includes a mixed collection. 113 allocationWork(20*1024*1024, 10*1024*1024); 114 System.out.println("Done allocationWork for mixed collections"); 115 116 usage = pool.getCollectionUsage().getUsed(); 117 System.out.println(poolName + ": usage after GC = " + usage); 118 if (usage <= 0) { 119 throw new RuntimeException(poolName + " found with zero usage"); 120 } 121 122 long newCollectionCount = collector.getCollectionCount(); 123 System.out.println(collectorName + ": collection count = " 124 + newCollectionCount); 125 long newCollectionTime = collector.getCollectionTime(); 126 System.out.println(collectorName + ": collection time = " 127 + newCollectionTime); 128 if (newCollectionCount <= collectionCount) { 129 throw new RuntimeException("No new collection"); 130 } 131 if (newCollectionTime <= collectionTime) { 132 throw new RuntimeException("Collector has not run some more"); 133 } 134 135 System.out.println("Test passed."); 136 } 137 138 public void allocationWork(long persistentTarget, long target) { 139 long persistentSizeAllocated = 0; 140 long sizeAllocated = 0; 141 char[] template = new char[10240]; 142 Random rand = new Random(); 143 PrimitiveIterator.OfInt indexiter = rand.ints().iterator(); 144 PrimitiveIterator.OfInt valueiter = rand.ints().iterator(); 145 146 Set<String> persistentStrings = new HashSet<>(1000); 147 while (persistentSizeAllocated < persistentTarget) { 148 for (int i = 0; i < 100; i++) { 149 template[Math.abs(indexiter.next() % 10240)] = (char)valueiter.nextInt(); 150 persistentStrings.add(new String(template)); 151 } 152 persistentSizeAllocated += 100*10240*2; 153 } 154 while (sizeAllocated < target) { 155 Set<String> strings = new HashSet<>(1000); 156 for (int i = 0; i < 1000; i++) { 157 template[Math.abs(indexiter.next() % 10240)] = (char)valueiter.nextInt(); 158 strings.add(new String(template)); 159 } 160 sizeAllocated += 1000*10240*2; 161 } 162 } 163 }