1 /* 2 * Copyright (c) 2011, 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 26 * @bug 7036199 27 * @summary Check that GarbageCollectionNotification contents are reasonable 28 * @author Frederic Parain 29 * @requires vm.opt.ExplicitGCInvokesConcurrent == null | vm.opt.ExplicitGCInvokesConcurrent == false 30 * @modules java.management/sun.management 31 * jdk.management 32 * @run main/othervm -Xms64m -Xmx64m GarbageCollectionNotificationContentTest 33 */ 34 35 import java.util.*; 36 import java.lang.management.*; 37 import java.lang.reflect.*; 38 import javax.management.*; 39 import javax.management.openmbean.*; 40 import com.sun.management.GarbageCollectionNotificationInfo; 41 import com.sun.management.GcInfo; 42 import java.security.AccessController; 43 import java.security.PrivilegedAction; 44 import java.lang.reflect.Field; 45 46 public class GarbageCollectionNotificationContentTest { 47 private static HashMap<String,GarbageCollectionNotificationInfo> listenerInvoked 48 = new HashMap<String,GarbageCollectionNotificationInfo>(); 49 static volatile long count = 0; 50 static volatile long number = 0; 51 static Object synchronizer = new Object(); 52 53 static class GcListener implements NotificationListener { handleNotification(Notification notif, Object handback)54 public void handleNotification(Notification notif, Object handback) { 55 String type = notif.getType(); 56 if (type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 57 GarbageCollectionNotificationInfo gcNotif = 58 GarbageCollectionNotificationInfo.from((CompositeData) notif.getUserData()); 59 String source = ((ObjectName)notif.getSource()).getCanonicalName(); 60 synchronized(synchronizer) { 61 if(listenerInvoked.get(source) == null) { 62 listenerInvoked.put(((ObjectName)notif.getSource()).getCanonicalName(),gcNotif); 63 count++; 64 if(count >= number) { 65 synchronizer.notify(); 66 } 67 } 68 } 69 } 70 } 71 } 72 main(String[] args)73 public static void main(String[] args) throws Exception { 74 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 75 final boolean isNotificationSupported = 76 sun.management.ManagementFactoryHelper.getVMManagement().isGcNotificationSupported(); 77 78 if(!isNotificationSupported) { 79 System.out.println("GC Notification not supported by the JVM, test skipped"); 80 return; 81 } 82 final ObjectName gcMXBeanPattern = 83 new ObjectName("java.lang:type=GarbageCollector,*"); 84 Set<ObjectName> names = 85 mbs.queryNames(gcMXBeanPattern, null); 86 if (names.isEmpty()) 87 throw new Exception("Test incorrect: no GC MXBeans"); 88 number = names.size(); 89 for (ObjectName n : names) { 90 if(mbs.isInstanceOf(n,"javax.management.NotificationEmitter")) { 91 listenerInvoked.put(n.getCanonicalName(),null); 92 GcListener listener = new GcListener(); 93 mbs.addNotificationListener(n, listener, null, null); 94 } 95 } 96 // Invocation of System.gc() to trigger major GC 97 System.gc(); 98 // Allocation of many short living and small objects to trigger minor GC 99 Object data[] = new Object[32]; 100 for(int i = 0; i<10000000; i++) { 101 data[i%32] = new int[8]; 102 } 103 int wakeup = 0; 104 synchronized(synchronizer) { 105 while(count != number) { 106 synchronizer.wait(10000); 107 wakeup++; 108 if(wakeup > 10) 109 break; 110 } 111 } 112 for (GarbageCollectionNotificationInfo notif : listenerInvoked.values() ) { 113 checkGarbageCollectionNotificationInfoContent(notif); 114 } 115 System.out.println("Test passed"); 116 } 117 checkGarbageCollectionNotificationInfoContent(GarbageCollectionNotificationInfo notif)118 private static void checkGarbageCollectionNotificationInfoContent(GarbageCollectionNotificationInfo notif) throws Exception { 119 System.out.println("GC notification for "+notif.getGcName()); 120 System.out.print("Action: "+notif.getGcAction()); 121 System.out.println(" Cause: "+notif.getGcCause()); 122 GcInfo info = notif.getGcInfo(); 123 System.out.print("GC Info #" + info.getId()); 124 System.out.print(" start:" + info.getStartTime()); 125 System.out.print(" end:" + info.getEndTime()); 126 System.out.println(" (" + info.getDuration() + "ms)"); 127 Map<String, MemoryUsage> usage = info.getMemoryUsageBeforeGc(); 128 129 List<String> pnames = new ArrayList<String>(); 130 for (Map.Entry entry : usage.entrySet() ) { 131 String poolname = (String) entry.getKey(); 132 pnames.add(poolname); 133 MemoryUsage busage = (MemoryUsage) entry.getValue(); 134 MemoryUsage ausage = (MemoryUsage) info.getMemoryUsageAfterGc().get(poolname); 135 if (ausage == null) { 136 throw new RuntimeException("After Gc Memory does not exist" + 137 " for " + poolname); 138 } 139 System.out.println("Usage for pool " + poolname); 140 System.out.println(" Before GC: " + busage); 141 System.out.println(" After GC: " + ausage); 142 143 checkMemoryUsage(poolname, busage, ausage); 144 } 145 146 // check if memory usage for all memory pools are returned 147 List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); 148 for (MemoryPoolMXBean p : pools ) { 149 if (!pnames.contains(p.getName())) { 150 throw new RuntimeException("GcInfo does not contain " + 151 "memory usage for pool " + p.getName()); 152 } 153 } 154 } 155 checkMemoryUsage(String poolname, MemoryUsage busage, MemoryUsage ausage)156 private static void checkMemoryUsage(String poolname, MemoryUsage busage, MemoryUsage ausage) throws Exception { 157 if (poolname.contains("Eden Space") && busage.getUsed() > 0) { 158 // Used size at Eden Space should be decreased or 159 if (busage.getUsed() <= ausage.getUsed()) { 160 throw new RuntimeException("Used size at Eden Space should be decreased."); 161 } 162 } 163 } 164 } 165