1/* 2 * Copyright (C) 2011 Google Inc. 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 17package libcore.java.lang.ref; 18 19import java.util.concurrent.CountDownLatch; 20import java.util.concurrent.atomic.AtomicBoolean; 21import java.util.concurrent.atomic.AtomicInteger; 22import junit.framework.TestCase; 23 24public final class FinalizeTest extends TestCase { 25 26 public void testFinalizeIsCalled() throws Exception { 27 AtomicBoolean finalized = new AtomicBoolean(); 28 createFinalizableObject(finalized); 29 30 FinalizationTester.induceFinalization(); 31 if (!finalized.get()) { 32 fail("object not yet finalized"); 33 } 34 } 35 36 /** 37 * Test verifies that runFinalization() does not mess up objects 38 * that should be finalized later on. http://b/6907299 39 */ 40 public void testInducedFinalization() throws Exception { 41 AtomicBoolean finalized1 = new AtomicBoolean(); 42 AtomicBoolean finalized2 = new AtomicBoolean(); 43 createFinalizableObject(finalized1); 44 createFinalizableObject(finalized2); 45 FinalizationTester.induceFinalization(); 46 if (!finalized1.get() || !finalized2.get()) { 47 fail("not yet finalized: " + finalized1.get() + " " + finalized2.get()); 48 } 49 } 50 51 /** Do not inline this method; that could break non-precise GCs. See FinalizationTester. */ 52 private X createFinalizableObject(final AtomicBoolean finalized) { 53 X result = new X() { 54 @Override protected void finalize() throws Throwable { 55 super.finalize(); 56 finalized.set(true); 57 } 58 }; 59 FinalizationTester.induceFinalization(); 60 // Dance around a bit to discourage dx from realizing that 'result' is no longer live. 61 boolean wasFinalized = finalized.get(); 62 if (wasFinalized) { 63 fail("finalizer called early"); // ...because 'result' is still live until we return. 64 } 65 // But we don't actually want to return 'result' because then we'd have to worry about 66 // the caller accidentally keeping it live. 67 return wasFinalized ? result : null; 68 } 69 70 static class X {} 71 72 // Helper function since we do not want a vreg to keep the allocated object live. 73 // For b/25851249 74 private void exceptionInConstructor() { 75 try { 76 new ConstructionFails(); 77 } catch (AssertionError expected) { 78 } 79 } 80 81 // http://b/issue?id=2136462 82 public void testBackFromTheDead() throws Exception { 83 exceptionInConstructor(); 84 FinalizationTester.induceFinalization(); 85 assertTrue("object whose constructor threw was not finalized", ConstructionFails.finalized); 86 } 87 88 static class ConstructionFails { 89 private static boolean finalized; 90 91 ConstructionFails() { 92 throw new AssertionError(); 93 } 94 95 @Override protected void finalize() throws Throwable { 96 finalized = true; 97 } 98 } 99 100 /** 101 * The finalizer watch dog exits the VM if any object takes more than 10 s 102 * to finalize. Check that objects near that limit are okay. 103 */ 104 public void testWatchdogDoesNotFailForObjectsThatAreNearTheDeadline() throws Exception { 105 CountDownLatch latch = new CountDownLatch(5); 106 createSlowFinalizer( 1, latch); 107 createSlowFinalizer(1000, latch); 108 createSlowFinalizer(2000, latch); 109 createSlowFinalizer(4000, latch); 110 createSlowFinalizer(8000, latch); 111 FinalizationTester.induceFinalization(); 112 latch.await(); 113 } 114 115 public void createSlowFinalizer(final long millis, final CountDownLatch latch) { 116 new Object() { 117 @Override protected void finalize() throws Throwable { 118 System.out.println("finalize sleeping " + millis + " ms"); 119 Thread.sleep(millis); 120 latch.countDown(); 121 } 122 }; 123 } 124 125 /** 126 * Make sure that System.runFinalization() returns even if the finalization 127 * queue is never completely empty. http://b/4193517 128 */ 129 public void testSystemRunFinalizationReturnsEvenIfQueueIsNonEmpty() throws Exception { 130 AtomicInteger count = new AtomicInteger(); 131 AtomicBoolean keepGoing = new AtomicBoolean(true); 132 createChainedFinalizer(count, keepGoing); 133 FinalizationTester.induceFinalization(); 134 keepGoing.set(false); 135 assertTrue(count.get() > 0); 136 } 137 138 public void createChainedFinalizer(final AtomicInteger counter, final AtomicBoolean keepGoing) { 139 new Object() { 140 @Override protected void finalize() throws Throwable { 141 int count = counter.incrementAndGet(); 142 System.out.println(count); 143 if (keepGoing.get()) { 144 createChainedFinalizer(counter, keepGoing); // recursive! 145 } 146 System.gc(); 147 FinalizationTester.enqueueReferences(); 148 } 149 }; 150 } 151} 152