1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2017 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import AAA.Derived; 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Worker public class Main { main(String[] args)20*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) { 21*795d594fSAndroid Build Coastguard Worker try { 22*795d594fSAndroid Build Coastguard Worker // Allocate memory for the "AAA.Derived" class name before eating memory. 23*795d594fSAndroid Build Coastguard Worker String aaaDerivedName = "AAA.Derived"; 24*795d594fSAndroid Build Coastguard Worker System.out.println("Eating all memory."); 25*795d594fSAndroid Build Coastguard Worker // Resolve VMClassLoader before eating all the memory since we can not fail 26*795d594fSAndroid Build Coastguard Worker // initialization of boot classpath classes. 27*795d594fSAndroid Build Coastguard Worker Class.forName("java.lang.VMClassLoader"); 28*795d594fSAndroid Build Coastguard Worker Object memory = eatAllMemory(); 29*795d594fSAndroid Build Coastguard Worker 30*795d594fSAndroid Build Coastguard Worker // This test assumes that Derived is not yet resolved. In some configurations 31*795d594fSAndroid Build Coastguard Worker // (notably interp-ac), Derived is already resolved by verifying Main at run 32*795d594fSAndroid Build Coastguard Worker // time. Therefore we cannot assume that we get a certain `value` and need to 33*795d594fSAndroid Build Coastguard Worker // simply check for consistency, i.e. `value == another_value`. 34*795d594fSAndroid Build Coastguard Worker int value = 0; 35*795d594fSAndroid Build Coastguard Worker try { 36*795d594fSAndroid Build Coastguard Worker // If the ArtMethod* is erroneously left in the DexCache, this 37*795d594fSAndroid Build Coastguard Worker // shall succeed despite the class Derived being unresolved so 38*795d594fSAndroid Build Coastguard Worker // far. Otherwise, we shall throw OOME trying to resolve it. 39*795d594fSAndroid Build Coastguard Worker value = Derived.foo(); 40*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 41*795d594fSAndroid Build Coastguard Worker value = -1; 42*795d594fSAndroid Build Coastguard Worker } 43*795d594fSAndroid Build Coastguard Worker int another_value = 0; 44*795d594fSAndroid Build Coastguard Worker try { 45*795d594fSAndroid Build Coastguard Worker // For comparison, try to resolve the class Derived directly. 46*795d594fSAndroid Build Coastguard Worker Class.forName(aaaDerivedName, false, Main.class.getClassLoader()); 47*795d594fSAndroid Build Coastguard Worker another_value = 42; 48*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError e) { 49*795d594fSAndroid Build Coastguard Worker another_value = -1; 50*795d594fSAndroid Build Coastguard Worker } 51*795d594fSAndroid Build Coastguard Worker boolean memoryWasAllocated = (memory != null); 52*795d594fSAndroid Build Coastguard Worker memory = null; 53*795d594fSAndroid Build Coastguard Worker System.out.println("memoryWasAllocated = " + memoryWasAllocated); 54*795d594fSAndroid Build Coastguard Worker System.out.println("match: " + (value == another_value)); 55*795d594fSAndroid Build Coastguard Worker if (value != another_value || (value != -1 && value != 42)) { 56*795d594fSAndroid Build Coastguard Worker // Mismatch or unexpected value, print additional debugging information. 57*795d594fSAndroid Build Coastguard Worker System.out.println("value: " + value); 58*795d594fSAndroid Build Coastguard Worker System.out.println("another_value: " + another_value); 59*795d594fSAndroid Build Coastguard Worker } 60*795d594fSAndroid Build Coastguard Worker } catch (Throwable t) { 61*795d594fSAndroid Build Coastguard Worker t.printStackTrace(System.out); 62*795d594fSAndroid Build Coastguard Worker } 63*795d594fSAndroid Build Coastguard Worker } 64*795d594fSAndroid Build Coastguard Worker exhaustJavaHeap(Object[] data, int index, int size)65*795d594fSAndroid Build Coastguard Worker private static int exhaustJavaHeap(Object[] data, int index, int size) { 66*795d594fSAndroid Build Coastguard Worker Runtime.getRuntime().gc(); 67*795d594fSAndroid Build Coastguard Worker // Let out-of-bound exception be thrown if we go past the array length. This should 68*795d594fSAndroid Build Coastguard Worker // never happen if the logic in the caller is right. The exception acts as an assertion. 69*795d594fSAndroid Build Coastguard Worker while (size != 0) { 70*795d594fSAndroid Build Coastguard Worker try { 71*795d594fSAndroid Build Coastguard Worker data[index] = new byte[size]; 72*795d594fSAndroid Build Coastguard Worker ++index; 73*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError oome) { 74*795d594fSAndroid Build Coastguard Worker size /= 2; 75*795d594fSAndroid Build Coastguard Worker } 76*795d594fSAndroid Build Coastguard Worker } 77*795d594fSAndroid Build Coastguard Worker return index; 78*795d594fSAndroid Build Coastguard Worker } 79*795d594fSAndroid Build Coastguard Worker eatAllMemory()80*795d594fSAndroid Build Coastguard Worker public static Object eatAllMemory() { 81*795d594fSAndroid Build Coastguard Worker Object[] result = null; 82*795d594fSAndroid Build Coastguard Worker int size = 1000000; 83*795d594fSAndroid Build Coastguard Worker // Make sure that there is no reclaimable memory in the heap. Otherwise we may throw 84*795d594fSAndroid Build Coastguard Worker // OOME to prevent GC thrashing, even if later allocations may succeed. 85*795d594fSAndroid Build Coastguard Worker Runtime.getRuntime().gc(); 86*795d594fSAndroid Build Coastguard Worker System.runFinalization(); 87*795d594fSAndroid Build Coastguard Worker // NOTE: There is a GC invocation in exhaustJavaHeap. So we don't need one here. 88*795d594fSAndroid Build Coastguard Worker 89*795d594fSAndroid Build Coastguard Worker while (result == null && size != 0) { 90*795d594fSAndroid Build Coastguard Worker try { 91*795d594fSAndroid Build Coastguard Worker result = new Object[size]; 92*795d594fSAndroid Build Coastguard Worker } catch (OutOfMemoryError oome) { 93*795d594fSAndroid Build Coastguard Worker size /= 2; 94*795d594fSAndroid Build Coastguard Worker } 95*795d594fSAndroid Build Coastguard Worker } 96*795d594fSAndroid Build Coastguard Worker if (result != null) { 97*795d594fSAndroid Build Coastguard Worker int index = 0; 98*795d594fSAndroid Build Coastguard Worker // Repeat to ensure there is no space left on the heap. 99*795d594fSAndroid Build Coastguard Worker index = exhaustJavaHeap(result, index, size); 100*795d594fSAndroid Build Coastguard Worker index = exhaustJavaHeap(result, index, /*size*/ 4); 101*795d594fSAndroid Build Coastguard Worker index = exhaustJavaHeap(result, index, /*size*/ 4); 102*795d594fSAndroid Build Coastguard Worker } 103*795d594fSAndroid Build Coastguard Worker return result; 104*795d594fSAndroid Build Coastguard Worker } 105*795d594fSAndroid Build Coastguard Worker } 106