1 /*
   2 * Copyright (c) 2015, 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 import java.util.LinkedList;
  25 import java.util.concurrent.Callable;
  26 
  27 /**
  28  * Helper class which allocates memory.
  29  *
  30  * Typical usage:
  31  * <pre>
  32  * {@code
  33  *           AllocationHelper allocator = new AllocationHelper(MAX_ITERATIONS, ARRAY_LENGTH, CHUNK_SIZE,
  34  *                   () -> (verifier()));
  35  *           // Allocate byte[CHUNK_SIZE] ARRAY_LENGTH times. Total allocated bytes will be CHUNK_SIZE * ARRAY_LENGTH + refs length.
  36  *           // Then invoke verifier and iterate MAX_ITERATIONS times.
  37  *           allocator.allocateMemoryAndVerify();
  38  * }
  39  * </pre>
  40  */
  41 public final class AllocationHelper {
  42 
  43     private final int arrayLength;
  44     private final int maxIterations;
  45     private final int chunkSize;
  46 
  47     // garbageStorage is used to store link to garbage to prevent optimization.
  48     private static Object garbageStorage;
  49     private byte garbage[][];
  50     private final Callable<?> verifierInstance;
  51 
  52     /**
  53      * Create an AllocationHelper with specified iteration count, array length, chunk size and verifier.
  54      *
  55      * @param maxIterations
  56      * @param arrayLength
  57      * @param chunkSize
  58      * @param verifier - Callable instance which will be invoked after all allocation cycle. Can be null;
  59      */
  60     public AllocationHelper(int maxIterations, int arrayLength, int chunkSize, Callable<?> verifier) {
  61         if ((arrayLength <= 0) || (maxIterations <= 0) || (chunkSize <= 0)) {
  62             throw new IllegalArgumentException("maxIterations, arrayLength and chunkSize should be greater then 0.");
  63         }
  64         this.arrayLength = arrayLength;
  65         this.maxIterations = maxIterations;
  66         this.chunkSize = chunkSize;
  67         verifierInstance = verifier;
  68         garbage = new byte[this.arrayLength][];
  69         garbageStorage = garbage;
  70     }
  71 
  72     private void allocateMemoryOneIteration() {
  73         for (int j = 0; j < arrayLength; j++) {
  74             garbage[j] = new byte[chunkSize];
  75         }
  76     }
  77 
  78     /**
  79      * Allocate memory and invoke Verifier during all iteration.
  80      *
  81      * @throws java.lang.Exception
  82      */
  83     public void allocateMemoryAndVerify() throws Exception {
  84         for (int i = 0; i < maxIterations; i++) {
  85             allocateMemoryOneIteration();
  86             if (verifierInstance != null) {
  87                 verifierInstance.call();
  88             }
  89         }
  90     }
  91 
  92     /**
  93      * The same as allocateMemoryAndVerify() but hides OOME
  94      *
  95      * @throws Exception
  96      */
  97     public void allocateMemoryAndVerifyNoOOME() throws Exception {
  98         try {
  99             allocateMemoryAndVerify();
 100         } catch (OutOfMemoryError e) {
 101             // exit on OOME
 102         }
 103     }
 104 
 105     /**
 106      * Release link to allocated garbage to make it available for further GC
 107      */
 108     public void release() {
 109         if (garbage != null) {
 110             garbage = null;
 111             garbageStorage = null;
 112         }
 113     }
 114 }