1 /* |
1 /* |
2 * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. |
7 * published by the Free Software Foundation. |
24 package nsk.share.gc.gp; |
24 package nsk.share.gc.gp; |
25 |
25 |
26 import java.io.IOException; |
26 import java.io.IOException; |
27 import java.io.PrintWriter; |
27 import java.io.PrintWriter; |
28 import java.io.StringWriter; |
28 import java.io.StringWriter; |
|
29 import java.lang.invoke.*; |
29 import java.util.*; |
30 import java.util.*; |
30 import nsk.share.gc.gp.array.*; |
31 import nsk.share.gc.gp.array.*; |
31 import nsk.share.gc.gp.string.*; |
32 import nsk.share.gc.gp.string.*; |
32 import nsk.share.gc.gp.list.*; |
33 import nsk.share.gc.gp.list.*; |
33 import nsk.share.gc.gp.tree.*; |
34 import nsk.share.gc.gp.tree.*; |
55 OOM_TYPE(String... expectedStrings) { |
56 OOM_TYPE(String... expectedStrings) { |
56 this.expectedStrings = expectedStrings; |
57 this.expectedStrings = expectedStrings; |
57 } |
58 } |
58 |
59 |
59 /** |
60 /** |
60 * Returns true if the given error message matches |
61 * Returns true if the given error message matches |
61 * one of expected strings. |
62 * one of expected strings. |
62 */ |
63 */ |
63 public boolean accept(String errorMessage) { |
64 public boolean accept(String errorMessage) { |
64 if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) { |
65 if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) { |
65 return true; |
66 return true; |
66 } |
67 } |
67 for (String s: expectedStrings) { |
68 for (String s: expectedStrings) { |
68 if (errorMessage.indexOf(s) != -1) { |
69 if (errorMessage.indexOf(s) != -1) { |
71 } |
72 } |
72 return false; |
73 return false; |
73 } |
74 } |
74 }; |
75 }; |
75 |
76 |
76 // Force loading of OOM_TYPE and calling of enum contrusctors when loading GarbageUtils class. |
77 // Force loading of OOM_TYPE and calling of enum constructors when loading GarbageUtils class. |
77 public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE }; |
78 public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE }; |
78 |
79 |
79 // Force early loading of classes that might otherwise unexpectedly fail |
80 // Force early loading of classes that might otherwise unexpectedly fail |
80 // class loading during testing due to high memory pressure. |
81 // class loading during testing due to high memory pressure. |
81 public static final StringWriter preloadStringWriter = new StringWriter(1); |
82 public static final StringWriter preloadStringWriter = new StringWriter(1); |
82 public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter); |
83 public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter); |
|
84 public static final Throwable preloadThrowable = new Throwable("preload"); |
83 |
85 |
84 private GarbageUtils() { |
86 private GarbageUtils() { |
85 } |
87 } |
86 |
88 |
87 /** |
89 /** |
191 */ |
193 */ |
192 public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) { |
194 public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) { |
193 return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY); |
195 return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY); |
194 } |
196 } |
195 |
197 |
|
198 static int numberOfOOMEs = 0; |
|
199 |
|
200 /** |
|
201 * Minimal wrapper of the main implementation. Catches any OOM |
|
202 * that might be thrown when rematerializing Objects when deoptimizing. |
|
203 * |
|
204 * It is Important that the impl is not inlined. |
|
205 */ |
|
206 |
|
207 public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) { |
|
208 try { |
|
209 // Using a methodhandle invoke of eatMemoryImpl to prevent inlining of it |
|
210 MethodHandles.Lookup lookup = MethodHandles.lookup(); |
|
211 MethodType mt = MethodType.methodType( |
|
212 int.class, |
|
213 ExecutionController.class, |
|
214 GarbageProducer.class, |
|
215 long.class, |
|
216 long.class, |
|
217 long.class, |
|
218 OOM_TYPE.class); |
|
219 MethodHandle eat = lookup.findStatic(GarbageUtils.class, "eatMemoryImpl", mt); |
|
220 return (int) eat.invoke(stresser, gp, initialFactor, minMemoryChunk, factor, type); |
|
221 } catch (OutOfMemoryError e) { |
|
222 return numberOfOOMEs++; |
|
223 } catch (Throwable t) { |
|
224 throw new RuntimeException(t); |
|
225 } |
|
226 } |
|
227 |
196 /** |
228 /** |
197 * Eat memory using given garbage producer. |
229 * Eat memory using given garbage producer. |
198 * |
230 * |
199 * Note that this method can throw Failure if any exception |
231 * Note that this method can throw Failure if any exception |
200 * is thrown while eating memory. To avoid OOM while allocating |
232 * is thrown while eating memory. To avoid OOM while allocating |
208 * @param minMemoryChunk determines when to stop |
240 * @param minMemoryChunk determines when to stop |
209 * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME |
241 * @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME |
210 * @param type of OutOfMemory Exception: Java heap space or Metadata space |
242 * @param type of OutOfMemory Exception: Java heap space or Metadata space |
211 * @return number of OOME occured |
243 * @return number of OOME occured |
212 */ |
244 */ |
213 public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) { |
245 |
214 int numberOfOOMEs = 0; |
246 public static int eatMemoryImpl(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) { |
|
247 numberOfOOMEs = 0; |
215 try { |
248 try { |
216 StringWriter sw = new StringWriter(10000); |
|
217 PrintWriter pw = new PrintWriter(sw); |
|
218 byte[] someMemory = new byte[200000]; //200 Kb |
249 byte[] someMemory = new byte[200000]; //200 Kb |
219 try { |
250 try { |
220 Runtime runtime = Runtime.getRuntime(); |
251 Runtime runtime = Runtime.getRuntime(); |
221 long maxMemory = runtime.maxMemory(); |
252 long maxMemory = runtime.maxMemory(); |
222 long maxMemoryChunk = maxMemory / initialFactor; |
253 long maxMemoryChunk = maxMemory / initialFactor; |
239 allocations = 0; |
270 allocations = 0; |
240 } |
271 } |
241 } catch (OutOfMemoryError e) { |
272 } catch (OutOfMemoryError e) { |
242 someMemory = null; |
273 someMemory = null; |
243 if (type != OOM_TYPE.ANY) { |
274 if (type != OOM_TYPE.ANY) { |
244 e.printStackTrace(pw); |
275 if (type.accept(e.toString())) { |
245 pw.close(); |
|
246 if (type.accept(sw.toString())) { |
|
247 numberOfOOMEs++; |
276 numberOfOOMEs++; |
248 } else { |
277 } else { |
249 // Trying to catch situation when Java generates OOM different type that test trying to catch |
278 // Trying to catch situation when Java generates OOM different type that test trying to catch |
250 throw new TestBug("Test throw OOM of unexpected type." + sw.toString()); |
279 throw new TestBug("Test throw OOM of unexpected type." + e.toString()); |
251 } |
280 } |
252 } else { |
281 } else { |
253 numberOfOOMEs++; |
282 numberOfOOMEs++; |
254 } |
283 } |
255 allocations = 0; |
284 allocations = 0; |
261 } |
290 } |
262 } |
291 } |
263 } catch (OutOfMemoryError e) { |
292 } catch (OutOfMemoryError e) { |
264 someMemory = null; |
293 someMemory = null; |
265 if (type != OOM_TYPE.ANY) { |
294 if (type != OOM_TYPE.ANY) { |
266 e.printStackTrace(pw); |
295 if (type.accept(e.toString())) { |
267 pw.close(); |
|
268 if (type.accept(sw.toString())) { |
|
269 numberOfOOMEs++; |
296 numberOfOOMEs++; |
270 } else { |
297 } else { |
271 // Trying to catch situation when Java generates OOM different type that test trying to catch |
298 // Trying to catch situation when Java generates OOM different type that test trying to catch |
272 throw new TestBug("Test throw OOM of unexpected type." + sw.toString()); |
299 throw new TestBug("Test throw OOM of unexpected type." + e.toString()); |
273 } |
300 } |
274 } else { |
301 } else { |
275 numberOfOOMEs++; |
302 numberOfOOMEs++; |
276 } |
303 } |
277 // all memory is eaten now even before we start, just return |
304 // all memory is eaten now even before we start, just return |