1 /* 2 * Copyright (c) 2003, 2024, 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 package nsk.monitoring.stress.lowmem; 24 25 import java.io.OutputStream; 26 import java.io.PrintStream; 27 import java.lang.management.ManagementFactory; 28 import java.lang.management.MemoryMXBean; 29 import java.lang.management.MemoryType; 30 import java.util.LinkedList; 31 import java.util.List; 32 import java.util.concurrent.atomic.AtomicBoolean; 33 import nsk.share.Log; 34 import nsk.share.TestFailure; 35 import nsk.share.gc.DefaultProducer; 36 import nsk.share.gc.GC; 37 import nsk.share.gc.ThreadedGCTest; 38 import nsk.share.gc.gp.GarbageProducer; 39 import nsk.share.gc.gp.classload.GeneratedClassProducer; 40 import nsk.monitoring.share.*; 41 import nsk.share.test.ExecutionController; 42 43 public class lowmem001 extends ThreadedGCTest { 44 45 // The max heap usage after whih we free memory and restart 46 static final int MAX_HEAP_USAGE = 70; 47 // isOOM is used to stop allocation and free resources 48 // immediately after first OOME 49 // really it could be only if we didn't check usage in time 50 static AtomicBoolean isOOM = new AtomicBoolean(false); 51 static ArgumentHandler argHandler; 52 MemoryMonitor monitor; 53 54 public static void main(String[] args) { 55 argHandler = new ArgumentHandler(args); 56 GC.runTest(new lowmem001(), args); 57 } 58 59 @Override 60 public void run() { 61 Log log = new Log(System.out); 62 // System.err is duplicated into buffer 63 // it should be empty 64 MyStream stream = new MyStream(System.err); 65 System.setErr(new PrintStream(stream)); 66 67 monitor = Monitor.getMemoryMonitor(log, argHandler); 68 try { 69 monitor.enableMonitoring(); 70 monitor.updateThresholds(); 71 super.run(); 72 monitor.disableMonitoring(); 73 } catch (Exception e) { 74 throw new TestFailure(e); 75 } 76 if (isOOM.get() == true) { 77 log.display("The OOME happened during test"); 78 // We control memory at 70 % 79 // each time when we want to eat 512 bytes 80 // if we got OOME it is really ugly 81 throw new TestFailure("OOME should not happened."); 82 } 83 if (!monitor.getPassedStatus()) { 84 throw new TestFailure("MemoryMonitor fails. See log."); 85 } 86 if (!stream.isEmpty()) { 87 String string = stream.getString(); 88 if (string.contains("java.lang.OutOfMemoryError")) { 89 log.display("WARNING: The System.err contains OutOfMemory."); 90 // the OOME is not error 91 log.complain(string); 92 return; 93 } 94 log.complain(string); 95 throw new TestFailure("Error stream is not empty."); 96 } 97 98 } 99 100 @Override 101 protected Runnable createRunnable(int i) { 102 String memory = argHandler.getTestedMemory(); 103 if (memory.equals(MemoryMonitor.HEAP_TYPE)) { 104 return new HeapStresser(); 105 } 106 if (memory.equals(MemoryMonitor.NONHEAP_TYPE)) { 107 return new ClassStresser(); 108 } 109 // mixed type 110 return i % 2 == 0 ? new HeapStresser() : new ClassStresser(); 111 } 112 113 /* 114 * Simple ClassLoader is used for non-heap stressing 115 * should be revised after permgen removal 116 */ 117 class ClassStresser extends Thread { 118 119 @Override 120 public void run() { 121 ExecutionController stresser = getExecutionController(); 122 GeneratedClassProducer gp = new GeneratedClassProducer(); 123 while (stresser.continueExecution()) { 124 try { 125 gp.create(0); 126 } catch (OutOfMemoryError e) { 127 // drop 'gc', reset Thresholds and start new iteration 128 monitor.resetThresholds(MemoryType.NON_HEAP); 129 return; 130 } 131 } 132 } 133 }; 134 135 class HeapStresser extends Thread { 136 137 final long chunkSize = 512; 138 List storage; 139 GarbageProducer gp = new DefaultProducer(); 140 141 142 @Override 143 public void run() { 144 storage = new LinkedList(); 145 ExecutionController stresser = getExecutionController(); 146 MemoryMXBean bean = ManagementFactory.getMemoryMXBean(); 147 148 while (stresser.continueExecution()) { 149 try { 150 storage.add(gp.create(chunkSize + new Object().hashCode() % 31)); 151 storage.add(gp.create(chunkSize)); 152 storage.remove(0); 153 if (isOOM.get() == true || !stresser.continueExecution()) { 154 stresser.finish(); 155 storage = null; 156 return; 157 } 158 if (Thread.currentThread().isInterrupted()) { 159 break; 160 } 161 // If memory is low free resources and restart 162 if (bean.getHeapMemoryUsage().getUsed() 163 > bean.getHeapMemoryUsage().getMax() * MAX_HEAP_USAGE / 100) { 164 storage = new LinkedList(); 165 monitor.resetThresholds(MemoryType.HEAP); 166 } 167 } catch (OutOfMemoryError e) { 168 // Let finish, the managment/memorymonitor could be 169 // corrupted after OOME 170 storage = null; 171 isOOM.set(true); 172 stresser.finish(); 173 return; 174 } 175 } 176 } 177 } 178 179 static class MyStream extends OutputStream { 180 181 PrintStream err; 182 183 public MyStream(PrintStream err) { 184 this.err = err; 185 } 186 private final static int SIZE = 100000; 187 private char[] value = new char[SIZE]; 188 private int count = 0; 189 190 // No additional memory allocation during write 191 @Override 192 public synchronized void write(int b) { 193 if (count < SIZE) { 194 value[count++] = (char) b; 195 } 196 try { 197 err.write(b); 198 } catch (OutOfMemoryError oome) { 199 isOOM.set(true); 200 } 201 } 202 203 public String getString() { 204 return new String(value, 0, count); 205 } 206 207 public boolean isEmpty() { 208 return count == 0; 209 } 210 } 211 } --- EOF ---