blob: cd36eff1606e25627e3878ea111061dc2ee3e977 [file] [log] [blame]
jeffhao5d1ac922011-09-29 17:41:15 -07001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Mathieu Chartiera61894d2015-04-23 16:32:54 -070017import java.lang.reflect.InvocationTargetException;
18import java.lang.reflect.Method;
19
jeffhao5d1ac922011-09-29 17:41:15 -070020public class Main {
21 static class ArrayMemEater {
Elliott Hughesff9af222013-04-11 18:13:31 -070022 static boolean sawOome;
23
24 static void blowup(char[][] holder) {
jeffhao5d1ac922011-09-29 17:41:15 -070025 try {
Elliott Hughesff9af222013-04-11 18:13:31 -070026 for (int i = 0; i < holder.length; ++i) {
Nicolas Geoffray74d6a822014-10-03 10:54:19 +000027 holder[i] = new char[1024 * 1024];
Elliott Hughesff9af222013-04-11 18:13:31 -070028 }
jeffhao5d1ac922011-09-29 17:41:15 -070029 } catch (OutOfMemoryError oome) {
Elliott Hughesff9af222013-04-11 18:13:31 -070030 ArrayMemEater.sawOome = true;
jeffhao5d1ac922011-09-29 17:41:15 -070031 }
jeffhao5d1ac922011-09-29 17:41:15 -070032 }
33 }
34
35 static class InstanceMemEater {
Elliott Hughesff9af222013-04-11 18:13:31 -070036 static boolean sawOome;
Mark Mendell8ed2e702014-08-18 22:19:06 -040037 static InstanceMemEater hook;
Elliott Hughesff9af222013-04-11 18:13:31 -070038
jeffhao5d1ac922011-09-29 17:41:15 -070039 InstanceMemEater next;
Elliott Hughesff9af222013-04-11 18:13:31 -070040 double d1, d2, d3, d4, d5, d6, d7, d8; // Bloat this object so we fill the heap faster.
jeffhao5d1ac922011-09-29 17:41:15 -070041
Elliott Hughesff9af222013-04-11 18:13:31 -070042 static InstanceMemEater allocate() {
jeffhao5d1ac922011-09-29 17:41:15 -070043 try {
Elliott Hughesff9af222013-04-11 18:13:31 -070044 return new InstanceMemEater();
jeffhao5d1ac922011-09-29 17:41:15 -070045 } catch (OutOfMemoryError e) {
Elliott Hughesff9af222013-04-11 18:13:31 -070046 InstanceMemEater.sawOome = true;
47 return null;
jeffhao5d1ac922011-09-29 17:41:15 -070048 }
jeffhao5d1ac922011-09-29 17:41:15 -070049 }
50
Elliott Hughesff9af222013-04-11 18:13:31 -070051 static void confuseCompilerOptimization(InstanceMemEater instance) {
Mark Mendell8ed2e702014-08-18 22:19:06 -040052 hook = instance;
jeffhao5d1ac922011-09-29 17:41:15 -070053 }
54 }
55
Lokesh Gidra52173962020-05-15 17:09:14 -070056 private static int exhaustJavaHeap(Object[] data, int index, int size) {
Lokesh Gidrab3146d02020-05-21 13:28:08 -070057 Runtime.getRuntime().gc();
Lokesh Gidra52173962020-05-15 17:09:14 -070058 while (index != data.length && size != 0) {
59 try {
60 data[index] = new byte[size];
61 ++index;
62 } catch (OutOfMemoryError oome) {
63 size /= 2;
64 }
65 }
66 return index;
67 }
68
Vladimir Markoa35510d2017-01-16 22:42:09 +000069 public static Object eatAllMemory() {
70 Object[] result = null;
71 int size = 1000000;
Hans Boehm2a846502020-04-28 15:11:21 -070072 // Make sure that there is no reclaimable memory in the heap. Otherwise we may throw
73 // OOME to prevent GC thrashing, even if later allocations may succeed.
74 Runtime.getRuntime().gc();
75 System.runFinalization();
Lokesh Gidrab3146d02020-05-21 13:28:08 -070076 // NOTE: There is a GC invocation in exhaustJavaHeap. So we don't need one here.
77
Vladimir Markoa35510d2017-01-16 22:42:09 +000078 while (result == null && size != 0) {
79 try {
80 result = new Object[size];
81 } catch (OutOfMemoryError oome) {
82 size /= 2;
83 }
84 }
85 if (result != null) {
86 int index = 0;
Lokesh Gidra52173962020-05-15 17:09:14 -070087 // Repeat to ensure there is no space left on the heap.
88 index = exhaustJavaHeap(result, index, size);
Lokesh Gidrab3146d02020-05-21 13:28:08 -070089 index = exhaustJavaHeap(result, index, /*size*/ 4);
90 index = exhaustJavaHeap(result, index, /*size*/ 4);
Vladimir Markoa35510d2017-01-16 22:42:09 +000091 }
92 return result;
93 }
94
Nicolas Geoffray74d6a822014-10-03 10:54:19 +000095 static boolean triggerArrayOOM() {
96 ArrayMemEater.blowup(new char[128 * 1024][]);
Elliott Hughesff9af222013-04-11 18:13:31 -070097 return ArrayMemEater.sawOome;
jeffhao5d1ac922011-09-29 17:41:15 -070098 }
99
Elliott Hughesff9af222013-04-11 18:13:31 -0700100 static boolean triggerInstanceOOM() {
101 InstanceMemEater memEater = InstanceMemEater.allocate();
jeffhao5d1ac922011-09-29 17:41:15 -0700102 InstanceMemEater lastMemEater = memEater;
103 do {
Elliott Hughesff9af222013-04-11 18:13:31 -0700104 lastMemEater.next = InstanceMemEater.allocate();
jeffhao5d1ac922011-09-29 17:41:15 -0700105 lastMemEater = lastMemEater.next;
106 } while (lastMemEater != null);
107 memEater.confuseCompilerOptimization(memEater);
Mark Mendell8ed2e702014-08-18 22:19:06 -0400108 InstanceMemEater.hook = null;
Elliott Hughesff9af222013-04-11 18:13:31 -0700109 return InstanceMemEater.sawOome;
jeffhao5d1ac922011-09-29 17:41:15 -0700110 }
111
112 public static void main(String[] args) {
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700113 if (triggerReflectionOOM()) {
114 System.out.println("Test reflection correctly threw");
115 }
Vladimir Markoa35510d2017-01-16 22:42:09 +0000116 if (triggerReflectionOOM2()) {
117 System.out.println("Test reflection2 correctly threw");
118 }
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700119
Nicolas Geoffray74d6a822014-10-03 10:54:19 +0000120 if (triggerArrayOOM()) {
Elliott Hughesff9af222013-04-11 18:13:31 -0700121 System.out.println("NEW_ARRAY correctly threw OOME");
122 }
123
124 if (triggerInstanceOOM()) {
125 System.out.println("NEW_INSTANCE correctly threw OOME");
126 }
jeffhao5d1ac922011-09-29 17:41:15 -0700127 }
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700128
129 static Object[] holder;
130
131 public static void blowup() throws Exception {
Mathieu Chartier30f530e2017-03-22 10:02:31 -0700132 int size = 2 * 1024 * 1024;
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700133 for (int i = 0; i < holder.length; ) {
134 try {
135 holder[i] = new char[size];
136 i++;
137 } catch (OutOfMemoryError oome) {
Mathieu Chartier30f530e2017-03-22 10:02:31 -0700138 size = size / 16;
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700139 if (size == 0) {
140 break;
141 }
142 }
143 }
144 holder[0] = new char[100000];
145 }
146
147 static boolean triggerReflectionOOM() {
148 try {
149 Class<?> c = Main.class;
Andreas Gampe166aaee2016-07-18 08:27:23 -0700150 Method m = c.getMethod("blowup");
Mathieu Chartiera61894d2015-04-23 16:32:54 -0700151 holder = new Object[1000000];
152 m.invoke(null);
153 holder = null;
154 System.out.println("Didn't throw from blowup");
155 } catch (OutOfMemoryError e) {
156 holder = null;
157 } catch (InvocationTargetException e) {
158 holder = null;
159 if (!(e.getCause() instanceof OutOfMemoryError)) {
160 System.out.println("InvocationTargetException cause not OOME " + e.getCause());
161 return false;
162 }
163 } catch (Exception e) {
164 holder = null;
165 System.out.println("Unexpected exception " + e);
166 return false;
167 }
168 return true;
169 }
Vladimir Markoa35510d2017-01-16 22:42:09 +0000170
171 static boolean triggerReflectionOOM2() {
172 Object memory = eatAllMemory();
173 boolean result = false;
174 try {
175 Main.class.getDeclaredMethods();
176 } catch (OutOfMemoryError e) {
177 result = true;
178 }
179 if (!result) {
180 boolean memoryWasAllocated = (memory != null);
181 memory = null;
182 System.out.println("memoryWasAllocated = " + memoryWasAllocated);
183 }
184 return result;
185 }
jeffhao5d1ac922011-09-29 17:41:15 -0700186}