LowMemoryTest2.java revision 9330:8b1f1c2a400f
1/* 2 * Copyright (c) 2004, 2013, 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 low memory detection of non-heap memory pool. 26 * 27 * The test set a listener to be notified when any of the non-heap pools 28 * exceed 80%. It then starts a thread that continuously loads classes. 29 * In the HotSpot implementation this causes metaspace to be consumed. 30 * Test completes when we the notification is received or an OutOfMemory 31 * is generated. 32 */ 33 34import java.lang.management.*; 35import javax.management.*; 36import javax.management.openmbean.CompositeData; 37import java.util.*; 38 39public class LowMemoryTest2 { 40 41 private static volatile boolean listenerInvoked = false; 42 43 private static String INDENT = " "; 44 45 static class SensorListener implements NotificationListener { 46 public void handleNotification(Notification notif, Object handback) { 47 String type = notif.getType(); 48 if (type.equals(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED) || 49 type.equals(MemoryNotificationInfo. 50 MEMORY_COLLECTION_THRESHOLD_EXCEEDED)) { 51 listenerInvoked = true; 52 MemoryNotificationInfo minfo = MemoryNotificationInfo. 53 from((CompositeData) notif.getUserData()); 54 55 System.out.print("Notification for " + minfo.getPoolName()); 56 System.out.print(" [type = " + type); 57 System.out.println(" count = " + minfo.getCount() + "]"); 58 System.out.println(INDENT + "usage = " + minfo.getUsage()); 59 } 60 } 61 } 62 63 // Loads classes Test100001, Test100002, .... until OutOfMemoryErrror or 64 // low memory notification 65 66 static class BoundlessLoaderThread extends ClassLoader implements Runnable { 67 68 static int count = 100000; 69 70 Class loadNext() throws ClassNotFoundException { 71 72 // public class TestNNNNNN extends java.lang.Object{ 73 // public TestNNNNNN(); 74 // Code: 75 // 0: aload_0 76 // 1: invokespecial #1; //Method java/lang/Object."<init>":()V 77 // 4: return 78 // } 79 80 int begin[] = { 81 0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x30, 82 0x00, 0x0a, 0x0a, 0x00, 0x03, 0x00, 0x07, 0x07, 83 0x00, 0x08, 0x07, 0x00, 0x09, 0x01, 0x00, 0x06, 84 0x3c, 0x69, 0x6e, 0x69, 0x74, 0x3e, 0x01, 0x00, 85 0x03, 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43, 86 0x6f, 0x64, 0x65, 0x0c, 0x00, 0x04, 0x00, 0x05, 87 0x01, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74 }; 88 89 int end [] = { 90 0x01, 0x00, 0x10, 91 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e, 92 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 93 0x00, 0x21, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 94 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04, 95 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 96 0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 97 0x00, 0x05, 0x2a, 0xb7, 0x00, 0x01, 0xb1, 0x00, 98 0x00, 0x00, 0x00, 0x00, 0x00 }; 99 100 101 // TestNNNNNN 102 103 int load_count = count++; 104 if (load_count > 999999) { 105 // The test will create a corrupt class file if the count 106 // exceeds 999999. Fix the test if this exception is thrown. 107 throw new RuntimeException("Load count exceeded"); 108 } 109 110 String name = "Test" + Integer.toString(load_count); 111 112 byte value[]; 113 try { 114 value = name.substring(4).getBytes("UTF-8"); 115 } catch (java.io.UnsupportedEncodingException x) { 116 throw new Error(); 117 } 118 119 // construct class file 120 121 int len = begin.length + value.length + end.length; 122 byte b[] = new byte[len]; 123 int i, pos=0; 124 for (i=0; i<begin.length; i++) { 125 b[pos++] = (byte)begin[i]; 126 } 127 for (i=0; i<value.length; i++) { 128 b[pos++] = value[i]; 129 } 130 for (i=0; i<end.length; i++) { 131 b[pos++] = (byte)end[i]; 132 } 133 134 return defineClass(name, b, 0, b.length); 135 } 136 137 /* 138 * Run method for thread that continuously loads classes. 139 * 140 * Note: Once the usage threshold has been exceeded the low memory 141 * detector thread will attempt to deliver its notification - this can 142 * potentially create a race condition with this thread contining to 143 * fill up metaspace. To avoid the low memory detector getting an 144 * OutOfMemory we throttle this thread once the threshold has been 145 * exceeded. 146 */ 147 public void run() { 148 List pools = ManagementFactory.getMemoryPoolMXBeans(); 149 boolean thresholdExceeded = false; 150 151 for (;;) { 152 try { 153 // the classes are small so we load 10 at a time 154 for (int i=0; i<10; i++) { 155 loadNext(); 156 } 157 } catch (ClassNotFoundException x) { 158 return; 159 } 160 if (listenerInvoked) { 161 return; 162 } 163 164 // if threshold has been exceeded we put in a delay to allow 165 // the low memory detector do its job. 166 if (thresholdExceeded) { 167 try { 168 Thread.currentThread().sleep(100); 169 } catch (InterruptedException x) { } 170 } else { 171 // check if the threshold has been exceeded 172 ListIterator i = pools.listIterator(); 173 while (i.hasNext()) { 174 MemoryPoolMXBean p = (MemoryPoolMXBean) i.next(); 175 if (p.getType() == MemoryType.NON_HEAP && 176 p.isUsageThresholdSupported()) 177 { 178 thresholdExceeded = p.isUsageThresholdExceeded(); 179 } 180 } 181 } 182 } 183 } 184 } 185 186 public static void main(String args[]) { 187 ListIterator iter = ManagementFactory.getMemoryPoolMXBeans().listIterator(); 188 189 // Set threshold of 80% of all NON_HEAP memory pools 190 // In the Hotspot implementation this means we should get a notification 191 // if the CodeCache or metaspace fills up. 192 193 while (iter.hasNext()) { 194 MemoryPoolMXBean p = (MemoryPoolMXBean) iter.next(); 195 if (p.getType() == MemoryType.NON_HEAP && p.isUsageThresholdSupported()) { 196 197 // set threshold 198 MemoryUsage mu = p.getUsage(); 199 long max = mu.getMax(); 200 if (max < 0) { 201 throw new RuntimeException("There is no maximum set for " 202 + p.getName() + " memory pool so the test is invalid"); 203 } 204 long threshold = (max * 80) / 100; 205 206 p.setUsageThreshold(threshold); 207 208 System.out.println("Selected memory pool for low memory " + 209 "detection."); 210 MemoryUtil.printMemoryPool(p); 211 212 } 213 } 214 215 216 // Install the listener 217 218 MemoryMXBean mm = ManagementFactory.getMemoryMXBean(); 219 SensorListener l2 = new SensorListener(); 220 221 NotificationEmitter emitter = (NotificationEmitter) mm; 222 emitter.addNotificationListener(l2, null, null); 223 224 // Start the thread loading classes 225 226 Thread thr = new Thread(new BoundlessLoaderThread()); 227 thr.start(); 228 229 // Wait for the thread to terminate 230 try { 231 thr.join(); 232 } catch (InterruptedException x) { 233 throw new RuntimeException(x); 234 } 235 236 if (listenerInvoked) { 237 System.out.println("Notification received - test passed."); 238 } else { 239 throw new RuntimeException("Test failed - notification not received!"); 240 } 241 } 242 243} 244