1 /*
  2  * Copyright (c) 2018, Red Hat, Inc. 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 /**
 26  * @test id=large
 27  * @summary Test allocation of large objects results in OOM, but will not crash the JVM
 28  * @requires vm.gc.Shenandoah
 29  * @library /test/lib
 30  * @run driver TestAllocOutOfMemory large
 31  */
 32 
 33 /**
 34  * @test id=heap
 35  * @summary Test allocation of a heap-sized object results in OOM, but will not crash the JVM
 36  * @requires vm.gc.Shenandoah
 37  * @library /test/lib
 38  * @run driver TestAllocOutOfMemory heap
 39  */
 40 
 41 /**
 42  * @test id=small
 43  * @summary Test allocation of small objects results in OOM, but will not crash the JVM
 44  * @requires vm.gc.Shenandoah
 45  * @library /test/lib
 46  * @run driver TestAllocOutOfMemory small
 47  */
 48 
 49 import jdk.test.lib.process.OutputAnalyzer;
 50 import jdk.test.lib.process.ProcessTools;
 51 
 52 public class TestAllocOutOfMemory {
 53 
 54     static volatile Object sink;
 55 
 56     public static void work(int size, int count) throws Exception {
 57         Object[] root = new Object[count];
 58         sink = root;
 59         for (int c = 0; c < count; c++) {
 60             root[c] = new Object[size];
 61         }
 62     }
 63 
 64     private static void allocate(String size, int multiplier) throws Exception {
 65         switch (size) {
 66             case "large":
 67                 work(1024 * 1024, 16 * multiplier);
 68                 break;
 69             case "heap":
 70                 work(16 * 1024 * 1024, multiplier);
 71                 break;
 72             case "small":
 73                 work(1, 16 * 1024 * 1024 * multiplier);
 74                 break;
 75             default:
 76                 throw new IllegalArgumentException("Usage: test [large|small|heap]");
 77         }
 78     }
 79 
 80     public static void main(String[] args) throws Exception {
 81         if (args.length > 2) {
 82             // Called from test, size is second argument, heap requested is third
 83             String size = args[1];
 84             long spec_heap = Integer.parseInt(args[2]);
 85 
 86             // The actual heap we get may be larger than the one we asked for
 87             // (particularly in the generational case)
 88             final long actual_heap = Runtime.getRuntime().maxMemory();
 89             int multiplier = 1;
 90             if (actual_heap > spec_heap) {
 91                 // A suitable multiplier is used, so as to allocate an
 92                 // amount appropriate to the larger actual heap size than what
 93                 // was specified.
 94                 multiplier = (int)((actual_heap + spec_heap - 1)/spec_heap);
 95             }
 96 
 97             allocate(size, multiplier);
 98             return;
 99         }
100 
101         // Called from jtreg, size is first argument
102         String size = args[0];
103         {
104             int heap = 16*1024*1024;      // -Xmx16m
105             expectFailure("-Xmx16m",
106                           "-XX:+UnlockExperimentalVMOptions",
107                           "-XX:+UseShenandoahGC",
108                           TestAllocOutOfMemory.class.getName(),
109                           "test", size, Integer.toString(heap));
110 
111             expectFailure("-Xmx16m",
112                           "-XX:+UnlockExperimentalVMOptions",
113                           "-XX:+UseShenandoahGC", "-XX:ShenandoahGCMode=generational",
114                           TestAllocOutOfMemory.class.getName(),
115                           "test", size, Integer.toString(heap));
116         }
117 
118         {
119             int heap = 1*1024*1024*1024;  // -Xmx1g
120             expectSuccess("-Xmx1g",
121                           "-XX:+UnlockExperimentalVMOptions",
122                           "-XX:+UseShenandoahGC",
123                           TestAllocOutOfMemory.class.getName(),
124                           "test", size, Integer.toString(heap));
125 
126             expectSuccess("-Xmx1g",
127                           "-XX:+UnlockExperimentalVMOptions",
128                           "-XX:+UseShenandoahGC", "-XX:ShenandoahGCMode=generational",
129                           TestAllocOutOfMemory.class.getName(),
130                           "test", size, Integer.toString(heap));
131         }
132     }
133 
134     private static void expectSuccess(String... args) throws Exception {
135         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args);
136         OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
137         analyzer.shouldHaveExitValue(0);
138         analyzer.shouldNotContain("java.lang.OutOfMemoryError: Java heap space");
139     }
140 
141     private static void expectFailure(String... args) throws Exception {
142         ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(args);
143         OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
144         analyzer.shouldHaveExitValue(1);
145         analyzer.shouldContain("java.lang.OutOfMemoryError: Java heap space");
146     }
147 }