1 /* 2 * Copyright (C) 2008 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 17 import java.lang.ref.Reference; 18 import java.lang.ref.WeakReference; 19 import java.util.ArrayList; 20 import java.util.List; 21 22 /** 23 * Some finalizer tests. 24 * 25 * This only works if System.runFinalization() causes finalizers to run 26 * immediately or very soon. 27 */ 28 public class Main { 29 private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik"); 30 snooze(int ms)31 private static void snooze(int ms) { 32 try { 33 Thread.sleep(ms); 34 } catch (InterruptedException ie) { 35 System.out.println("Snooze: " + ie.getMessage()); 36 } 37 } 38 makeRef()39 public static WeakReference<FinalizerTest> makeRef() { 40 FinalizerTest ft = new FinalizerTest("wahoo"); 41 WeakReference<FinalizerTest> ref = new WeakReference<FinalizerTest>(ft); 42 ft = null; 43 return ref; 44 } 45 wimpString(final WeakReference<FinalizerTest> wimp)46 public static String wimpString(final WeakReference<FinalizerTest> wimp) { 47 /* 48 * Do the work in another thread, so there is no danger of a 49 * conservative reference to ft leaking onto the main thread's 50 * stack. 51 */ 52 53 final String[] s = new String[1]; 54 Thread t = new Thread() { 55 public void run() { 56 FinalizerTest ref = wimp.get(); 57 if (ref != null) { 58 s[0] = ref.toString(); 59 } 60 } 61 }; 62 63 t.start(); 64 65 try { 66 t.join(); 67 } catch (InterruptedException ie) { 68 throw new RuntimeException(ie); 69 } 70 71 return s[0]; 72 } 73 main(String[] args)74 public static void main(String[] args) { 75 WeakReference<FinalizerTest> wimp = makeRef(); 76 // Reference ft so we are sure the WeakReference cannot be cleared. 77 // Note: This is very fragile. It was previously in a helper function but that 78 // doesn't work for JIT-on-first-use with --gcstress where the object would be 79 // collected when JIT internally allocates an array. Also adding a scope around 80 // the keepLive lifetime somehow keeps a non-null `keepLive` around and makes 81 // the test fail (even when keeping the `null` assignment). b/76454261 82 FinalizerTest keepLive = wimp.get(); 83 System.out.println("wimp: " + wimpString(wimp)); 84 Reference.reachabilityFence(keepLive); 85 keepLive = null; // Clear the reference. 86 87 /* this will try to collect and finalize ft */ 88 System.out.println("gc"); 89 Runtime.getRuntime().gc(); 90 91 System.out.println("wimp: " + wimpString(wimp)); 92 System.out.println("finalize"); 93 System.runFinalization(); 94 System.out.println("wimp: " + wimpString(wimp)); 95 96 System.out.println("sleep"); 97 snooze(1000); 98 99 System.out.println("reborn: " + FinalizerTest.mReborn); 100 System.out.println("wimp: " + wimpString(wimp)); 101 System.out.println("reset reborn"); 102 Runtime.getRuntime().gc(); 103 FinalizerTest.mReborn = FinalizerTest.mNothing; 104 System.out.println("gc + finalize"); 105 System.gc(); 106 System.runFinalization(); 107 108 System.out.println("sleep"); 109 snooze(1000); 110 111 System.out.println("reborn: " + FinalizerTest.mReborn); 112 System.out.println("wimp: " + wimpString(wimp)); 113 // Test runFinalization with multiple objects. 114 runFinalizationTest(); 115 } 116 117 static class FinalizeCounter { 118 public static final int maxCount = 1024; 119 public static boolean finalized[] = new boolean[maxCount]; 120 private static Object finalizeLock = new Object(); 121 private static volatile int finalizeCount = 0; 122 private int index; getCount()123 static int getCount() { 124 return finalizeCount; 125 } printNonFinalized()126 static void printNonFinalized() { 127 for (int i = 0; i < maxCount; ++i) { 128 if (!FinalizeCounter.finalized[i]) { 129 System.out.println("Element " + i + " was not finalized"); 130 } 131 } 132 } FinalizeCounter(int index)133 FinalizeCounter(int index) { 134 this.index = index; 135 } finalize()136 protected void finalize() { 137 synchronized(finalizeLock) { 138 ++finalizeCount; 139 finalized[index] = true; 140 } 141 } 142 } 143 allocFinalizableObjects(int count)144 private static void allocFinalizableObjects(int count) { 145 Object[] objs = new Object[count]; 146 for (int i = 0; i < count; ++i) { 147 objs[i] = new FinalizeCounter(i); 148 } 149 } 150 runFinalizationTest()151 private static void runFinalizationTest() { 152 allocFinalizableObjects(FinalizeCounter.maxCount); 153 Runtime.getRuntime().gc(); 154 System.runFinalization(); 155 if (FinalizeCounter.getCount() != FinalizeCounter.maxCount) { 156 if (isDalvik) { 157 // runFinalization is "expend effort", only ART makes a strong effort all finalizers ran. 158 System.out.println("Finalized " + FinalizeCounter.getCount() + " / " + FinalizeCounter.maxCount); 159 // Print out all the finalized elements. 160 FinalizeCounter.printNonFinalized(); 161 } 162 // Try to sleep for a couple seconds to see if the objects became finalized after. 163 try { 164 java.lang.Thread.sleep(2000); 165 } catch (InterruptedException e) { 166 throw new AssertionError(e); 167 } 168 } 169 System.out.println("After sleep finalized " + FinalizeCounter.getCount() + " / " + FinalizeCounter.maxCount); 170 FinalizeCounter.printNonFinalized(); 171 } 172 173 public static class FinalizerTest { 174 public static FinalizerTest mNothing = new FinalizerTest("nothing"); 175 public static FinalizerTest mReborn = mNothing; 176 177 private final String message; 178 private boolean finalized = false; 179 FinalizerTest(String message)180 public FinalizerTest(String message) { 181 this.message = message; 182 } 183 toString()184 public String toString() { 185 return "[FinalizerTest message=" + message + 186 ", finalized=" + finalized + "]"; 187 } 188 finalize()189 protected void finalize() { 190 finalized = true; 191 mReborn = this; 192 } 193 } 194 } 195