Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java
41162 views
/*1* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package nsk.share.gc.gp;2425import java.io.IOException;26import java.io.PrintWriter;27import java.io.StringWriter;28import java.lang.invoke.*;29import java.util.*;30import nsk.share.gc.gp.array.*;31import nsk.share.gc.gp.string.*;32import nsk.share.gc.gp.list.*;33import nsk.share.gc.gp.tree.*;34import nsk.share.gc.gp.misc.*;35import nsk.share.gc.gp.classload.*;36import nsk.share.gc.Memory;37import nsk.share.TestBug;38import nsk.share.test.*;3940/**41* Utility methods for garbage producers.42*/43public final class GarbageUtils {44private static final int ALLOCATION_LIMIT = 50000000; //50 Mb45private static GarbageProducers garbageProducers;46private static List<GarbageProducer> primitiveArrayProducers;47private static List<GarbageProducer> arrayProducers;48private static final GarbageProducer byteArrayProducer = new ByteArrayProducer();49public static enum OOM_TYPE {50ANY (),51HEAP("Java heap space"),52METASPACE("Metaspace", "Compressed class space");5354private final String[] expectedStrings;55OOM_TYPE(String... expectedStrings) {56this.expectedStrings = expectedStrings;57}5859/**60* Returns true if the given error message matches61* one of expected strings.62*/63public boolean accept(String errorMessage) {64if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) {65return true;66}67for (String s: expectedStrings) {68if (errorMessage.indexOf(s) != -1) {69return true;70}71}72return false;73}74};7576// Force loading of OOM_TYPE and calling of enum constructors when loading GarbageUtils class.77public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE };7879// Force early loading of classes that might otherwise unexpectedly fail80// class loading during testing due to high memory pressure.81public static final StringWriter preloadStringWriter = new StringWriter(1);82public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter);83public static final Throwable preloadThrowable = new Throwable("preload");8485private GarbageUtils() {86}8788/**89* Eat memory using execution controller that waits for 2 minutes.90* @return number of OOME occured91*/92public static int eatMemory() {93return eatMemory(2 * 60 * 1000);94}9596/**97* Eat memory using execution controller that waits for timeout.98* @return number of OOME occured99*/100public static int eatMemory(final long timeout) {101return eatMemory(new ExecutionController() {102final long initialTime = System.currentTimeMillis();103104@Override105public void start(long stdIterations) {}106107@Override108public boolean iteration() {return false;}109110@Override111public boolean continueExecution() {112return System.currentTimeMillis() - initialTime < timeout;113}114115@Override116public long getIteration() {return 0;}117118@Override119public void finish() {}120});121}122123124/**125* Eat memory using given execution controller and garbage producer.126*127* @param stresser execution controller128* @param gp garbage producer129* @return number of OOME occured130*/131public static int eatMemory(ExecutionController stresser) {132return eatMemory(stresser, byteArrayProducer, 50, 100, 2, OOM_TYPE.ANY);133}134135/**136* Eat memory using given execution controller and garbage producer.137*138* @param stresser execution controller139* @param gp garbage producer140* @return number of OOME occured141*/142public static int eatMemory(ExecutionController stresser, GarbageProducer gp) {143return eatMemory(stresser, gp, 50, 100, 2, OOM_TYPE.ANY);144}145146/**147* Eat memory using given garbage producer and given factor.148*149* @param gp garbage producer150* @param factor factor to divide the array size by151* @return number of OOME occured152*/153public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long factor) {154return eatMemory(stresser, gp, 50, 100, factor, OOM_TYPE.ANY);155}156157/**158* Eat memory using default(byte[]) garbage producer.159*160* Note that this method can throw Failure if any exception161* is thrown while eating memory. To avoid OOM while allocating162* exception we preallocate it before the lunch starts. It means163* that exception stack trace does not correspond to the place164* where exception is thrown, but points at start of the method.165*166* @param stresser stresser167* @param initialFactor determines which portion of initial memory initial chunk will be168* @param minMemoryChunk determines when to stop169* @param factor factor to divide the array size by170* @return number of OOME occured171*/172public static int eatMemory(ExecutionController stresser,long initialFactor, long minMemoryChunk, long factor) {173return eatMemory(stresser, byteArrayProducer, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);174}175176/**177* Eat memory using given garbage producer.178*179* Note that this method can throw Failure if any exception180* is thrown while eating memory. To avoid OOM while allocating181* exception we preallocate it before the lunch starts. It means182* that exception stack trace does not correspond to the place183* where exception is thrown, but points at start of the method.184*185* @param stresser stresser to use186* @param gp garbage producer187* @param initialFactor determines which portion of initial memory initial chunk will be188* @param minMemoryChunk determines when to stop189* @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME190* @param type of OutOfMemory Exception: Java heap space or Metadata space191* @return number of OOME occured192*/193public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) {194return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);195}196197static int numberOfOOMEs = 0;198199/**200* Minimal wrapper of the main implementation. Catches any OOM201* that might be thrown when rematerializing Objects when deoptimizing.202*203* It is Important that the impl is not inlined.204*/205206public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) {207try {208// Using a methodhandle invoke of eatMemoryImpl to prevent inlining of it209MethodHandles.Lookup lookup = MethodHandles.lookup();210MethodType mt = MethodType.methodType(211int.class,212ExecutionController.class,213GarbageProducer.class,214long.class,215long.class,216long.class,217OOM_TYPE.class);218MethodHandle eat = lookup.findStatic(GarbageUtils.class, "eatMemoryImpl", mt);219return (int) eat.invoke(stresser, gp, initialFactor, minMemoryChunk, factor, type);220} catch (OutOfMemoryError e) {221return numberOfOOMEs++;222} catch (Throwable t) {223throw new RuntimeException(t);224}225}226227/**228* Eat memory using given garbage producer.229*230* Note that this method can throw Failure if any exception231* is thrown while eating memory. To avoid OOM while allocating232* exception we preallocate it before the lunch starts. It means233* that exception stack trace does not correspond to the place234* where exception is thrown, but points at start of the method.235*236* @param stresser stresser to use237* @param gp garbage producer238* @param initialFactor determines which portion of initial memory initial chunk will be239* @param minMemoryChunk determines when to stop240* @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME241* @param type of OutOfMemory Exception: Java heap space or Metadata space242* @return number of OOME occured243*/244245public static int eatMemoryImpl(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) {246numberOfOOMEs = 0;247try {248byte[] someMemory = new byte[200000]; //200 Kb249try {250Runtime runtime = Runtime.getRuntime();251long maxMemory = runtime.maxMemory();252long maxMemoryChunk = maxMemory / initialFactor;253long chunk = maxMemoryChunk;254chunk = chunk > ALLOCATION_LIMIT ? ALLOCATION_LIMIT : chunk;255int allocations = 0;256List<Object> storage = new ArrayList<Object>();257258while (chunk > minMemoryChunk && stresser.continueExecution()) {259try {260storage.add(gp.create(chunk));261if (Thread.currentThread().isInterrupted()) {262return numberOfOOMEs;263}264// if we are able to eat chunk*factor let265// try to increase size of chunk266if (chunk * factor < maxMemoryChunk267&& factor != 0 && allocations++ == factor + 1) {268chunk = chunk * factor;269allocations = 0;270}271} catch (OutOfMemoryError e) {272someMemory = null;273if (type != OOM_TYPE.ANY) {274if (type.accept(e.toString())) {275numberOfOOMEs++;276} else {277// Trying to catch situation when Java generates OOM different type that test trying to catch278throw new TestBug("Test throw OOM of unexpected type." + e.toString());279}280} else {281numberOfOOMEs++;282}283allocations = 0;284if (factor == 0) {285return numberOfOOMEs;286} else {287chunk = chunk / factor;288}289}290}291} catch (OutOfMemoryError e) {292someMemory = null;293if (type != OOM_TYPE.ANY) {294if (type.accept(e.toString())) {295numberOfOOMEs++;296} else {297// Trying to catch situation when Java generates OOM different type that test trying to catch298throw new TestBug("Test throw OOM of unexpected type." + e.toString());299}300} else {301numberOfOOMEs++;302}303// all memory is eaten now even before we start, just return304}305} catch (OutOfMemoryError e) {306numberOfOOMEs++;307}308return numberOfOOMEs;309}310311/**312* Get all primitive array producers.313*/314public static List<GarbageProducer> getPrimitiveArrayProducers() {315return getGarbageProducers().getPrimitiveArrayProducers();316}317318/**319* Get all array producers.320*/321public static List<GarbageProducer> getArrayProducers() {322return getGarbageProducers().getArrayProducers();323}324325/**326* Determine size of each object in array which will occupy given327* memory with distribution determined by given memory strategy.328*/329public static long getArraySize(long memory, MemoryStrategy memoryStrategy) {330return memoryStrategy.getSize(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());331}332333/**334* Determine object count in array which will occupy given335* memory with distribution determined by given memory strategy.336*/337public static int getArrayCount(long memory, MemoryStrategy memoryStrategy) {338return memoryStrategy.getCount(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());339}340341/**342* Get garbage producer by identifier.343*344* @param id identifier345* @return garbage producer for this identifier346*/347public static GarbageProducer getGarbageProducer(String id) {348if (id == null || id.equals("byteArr"))349return new ByteArrayProducer();350else if (id.equals("booleanArr"))351return new BooleanArrayProducer();352else if (id.equals("shortArr"))353return new ShortArrayProducer();354else if (id.equals("charArr"))355return new CharArrayProducer();356else if (id.equals("intArr"))357return new IntArrayProducer();358else if (id.equals("longArr"))359return new LongArrayProducer();360else if (id.equals("floatArr"))361return new FloatArrayProducer();362else if (id.equals("doubleArr"))363return new DoubleArrayProducer();364else if (id.equals("objectArr"))365return new ObjectArrayProducer();366else if (id.equals("randomString"))367return new RandomStringProducer();368else if (id.equals("simpleString"))369return new SimpleStringProducer();370else if (id.startsWith("interned("))371return new InternedStringProducer(getGarbageProducer(getInBrackets(id)));372else if (id.startsWith("linearList("))373return new LinearListProducer(MemoryStrategy.fromString(getInBrackets(id)));374else if (id.startsWith("circularList("))375return new CircularListProducer(MemoryStrategy.fromString(getInBrackets(id)));376else if (id.startsWith("nonbranchyTree("))377return new NonbranchyTreeProducer(MemoryStrategy.fromString(getInBrackets(id)));378else if (id.equals("class"))379return new GeneratedClassProducer();380else if (id.startsWith("hashed("))381return new HashedGarbageProducer(getGarbageProducer(getInBrackets(id)));382else if (id.startsWith("random("))383return new RandomProducer(getGarbageProducerList(getInBrackets(id)));384else if (id.startsWith("twofields("))385return new TwoFieldsObjectProducer(getGarbageProducer(getInBrackets(id)));386else if (id.startsWith("arrayof("))387return new ArrayOfProducer(getGarbageProducer(getInBrackets(id)));388else if (id.startsWith("trace("))389return new TraceProducer(getGarbageProducer(getInBrackets(id)));390else391throw new TestBug("Invalid garbage producer identifier: " + id);392}393394private static String getInBrackets(String s) {395int n1 = s.indexOf('(');396if (n1 == -1)397throw new TestBug("Opening bracket not found: " + s);398int n2 = s.lastIndexOf(')');399if (n2 == -1)400throw new TestBug("Closing bracket not found: " + s);401return s.substring(n1 + 1, n2);402}403404private static List<GarbageProducer> getGarbageProducerList(String s) {405if (s.equals("primitiveArrays"))406return getPrimitiveArrayProducers();407else if (s.equals("arrays"))408return getArrayProducers();409else {410String[] ids = s.split(",");411List<GarbageProducer> garbageProducers = new ArrayList<GarbageProducer>(ids.length);412for (int i = 0; i < ids.length; ++i)413garbageProducers.add(getGarbageProducer(ids[i]));414return garbageProducers;415//throw new TestBug("Invalid id for list of garbage producers: " + id);416}417}418419public static GarbageProducers getGarbageProducers() {420if (garbageProducers == null)421garbageProducers = new GarbageProducers();422return garbageProducers;423}424}425426427