1 /* 2 * Copyright (c) 2011, 2015, 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 GarbageCollection notification are thrown by every GarbageCollectorMXBean 28 * @author Frederic Parain 29 * @requires vm.opt.ExplicitGCInvokesConcurrent == null | vm.opt.ExplicitGCInvokesConcurrent == false 30 * @modules jdk.management 31 * @run main/othervm GarbageCollectionNotificationTest 32 */ 33 34 import java.util.*; 35 import java.lang.management.*; 36 import java.lang.reflect.*; 37 import javax.management.*; 38 import javax.management.openmbean.*; 39 import com.sun.management.GarbageCollectionNotificationInfo; 40 import com.sun.management.GcInfo; 41 import java.security.AccessController; 42 import java.security.PrivilegedAction; 43 import java.lang.reflect.Field; 44 45 public class GarbageCollectionNotificationTest { 46 private static HashMap<String,Boolean> listenerInvoked = new HashMap<String,Boolean>(); 47 static volatile long count = 0; 48 static volatile long number = 0; 49 static Object synchronizer = new Object(); 50 51 static class GcListener implements NotificationListener { 52 public void handleNotification(Notification notif, Object handback) { 53 String type = notif.getType(); 54 if (type.equals(GarbageCollectionNotificationInfo.GARBAGE_COLLECTION_NOTIFICATION)) { 55 GarbageCollectionNotificationInfo gcNotif = 56 GarbageCollectionNotificationInfo.from((CompositeData) notif.getUserData()); 57 String source = ((ObjectName)notif.getSource()).getCanonicalName(); 58 synchronized(synchronizer) { 59 if(!listenerInvoked.get(source)) { 60 listenerInvoked.put(((ObjectName)notif.getSource()).getCanonicalName(),true); 61 count++; 62 if(count >= number) { 63 synchronizer.notify(); 64 } 65 } 66 } 67 } 68 } 69 } 70 71 public static void main(String[] args) throws Exception { 72 MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); 73 final Boolean isNotificationSupported = AccessController.doPrivileged (new PrivilegedAction<Boolean>() { 74 public Boolean run() { 75 try { 76 Class cl = Class.forName("sun.management.VMManagementImpl"); 77 Field f = cl.getDeclaredField("gcNotificationSupport"); 78 f.setAccessible(true); 79 return f.getBoolean(null); 80 } catch(ClassNotFoundException e) { 81 return false; 82 } catch(NoSuchFieldException e) { 83 return false; 84 } catch(IllegalAccessException e) { 85 return false; 86 } 87 } 88 }); 89 if(!isNotificationSupported) { 90 System.out.println("GC Notification not supported by the JVM, test skipped"); 91 return; 92 } 93 final ObjectName gcMXBeanPattern = 94 new ObjectName("java.lang:type=GarbageCollector,*"); 95 Set<ObjectName> names = 96 mbs.queryNames(gcMXBeanPattern, null); 97 if (names.isEmpty()) 98 throw new Exception("Test incorrect: no GC MXBeans"); 99 number = names.size(); 100 for (ObjectName n : names) { 101 if(mbs.isInstanceOf(n,"javax.management.NotificationEmitter")) { 102 listenerInvoked.put(n.getCanonicalName(),false); 103 GcListener listener = new GcListener(); 104 mbs.addNotificationListener(n, listener, null, null); 105 } 106 } 107 // Invocation of System.gc() to trigger major GC 108 System.gc(); 109 // Allocation of many short living and small objects to trigger minor GC 110 Object data[] = new Object[32]; 111 for(int i = 0; i<100000000; i++) { 112 data[i%32] = new int[8]; 113 } 114 int wakeup = 0; 115 synchronized(synchronizer) { 116 while(count != number) { 117 synchronizer.wait(10000); 118 wakeup++; 119 if(wakeup > 10) 120 break; 121 } 122 } 123 for (String source : listenerInvoked.keySet()) { 124 if(!listenerInvoked.get(source)) 125 throw new Exception("Test incorrect: notifications have not been sent for " 126 + source); 127 } 128 System.out.println("Test passed"); 129 } 130 }