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