1 /*
   2  * Copyright (c) 2018, 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 import java.lang.instrument.ClassFileTransformer;
  26 import java.lang.instrument.Instrumentation;
  27 import java.lang.instrument.IllegalClassFormatException;
  28 import java.security.ProtectionDomain;
  29 
  30 // This test is sensitive to -Xmx. It must be run with -xmx64m.
  31 // Running with a different -Xmx requires changing the parameters and careful re-testing.
  32 public class HumongousDuringDumpTransformer implements ClassFileTransformer {
  33     public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
  34                             ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
  35         if (name.equals("Hello")) {
  36             try {
  37                 makeHumongousRegions();
  38             } catch (Throwable t) {
  39                 array = null;
  40                 humon = null;
  41                 System.out.println("Unexpected error: " + t);
  42                 t.printStackTrace();
  43             }
  44         }
  45         array = null;
  46         return null;
  47     }
  48 
  49     private static Instrumentation savedInstrumentation;
  50 
  51     public static void premain(String agentArguments, Instrumentation instrumentation) {
  52         long xmx = Runtime.getRuntime().maxMemory();
  53         if (xmx < 60 * 1024 * 1024 || xmx > 80 * 1024 * 1024) {
  54             System.out.println("Running with incorrect heap size: " + xmx);
  55             System.exit(1);
  56         }
  57 
  58         System.out.println("ClassFileTransformer.premain() is called");
  59         instrumentation.addTransformer(new HumongousDuringDumpTransformer(), /*canRetransform=*/true);
  60         savedInstrumentation = instrumentation;
  61     }
  62 
  63     public static Instrumentation getInstrumentation() {
  64         return savedInstrumentation;
  65     }
  66 
  67     public static void agentmain(String args, Instrumentation inst) throws Exception {
  68         premain(args, inst);
  69     }
  70 
  71     Object[] array;
  72 
  73     static final int DUMMY_SIZE = 4096 - 16 - 8;
  74     static final int HUMON_SIZE = 4 * 1024 * 1024 - 16 - 8;
  75     static final int SKIP = 13;
  76 
  77     byte humon[] = null;
  78     boolean first = true;
  79 
  80     public synchronized void makeHumongousRegions() {
  81         if (!first) {
  82             return;
  83         }
  84         System.out.println("===============================================================================");
  85         first = false;
  86 
  87         int total = 0;
  88         array = new Object[100000];
  89         System.out.println(array);
  90 
  91         // (1) Allocate about 8MB of old objects.
  92         for (int n=0, i=0; total < 8 * 1024 * 1024; n++) {
  93             // Make enough allocations to cause a GC (for 64MB heap) to create
  94             // old regions.
  95             //
  96             // But don't completely fill up the heap. That would cause OOM and
  97             // may not be handled gracefully inside class transformation!
  98             Object x = new byte[DUMMY_SIZE];
  99             if ((n  % SKIP) == 0) {
 100                 array[i++] = x;
 101                 total += DUMMY_SIZE;
 102             }
 103         }
 104 
 105         System.gc();
 106 
 107         // (2) Now allocate a humongous array. It will sit above the 8MB of old regions.
 108         humon = new byte[HUMON_SIZE];
 109         array = null;
 110         System.gc();
 111     }
 112 }