/*
|
* Copyright (C) 2008 The Android Open Source Project
|
*
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
* you may not use this file except in compliance with the License.
|
* You may obtain a copy of the License at
|
*
|
* http://www.apache.org/licenses/LICENSE-2.0
|
*
|
* Unless required by applicable law or agreed to in writing, software
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* See the License for the specific language governing permissions and
|
* limitations under the License.
|
*/
|
|
import java.lang.ref.Reference;
|
import java.lang.ref.WeakReference;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
/**
|
* Some finalizer tests.
|
*
|
* This only works if System.runFinalization() causes finalizers to run
|
* immediately or very soon.
|
*/
|
public class Main {
|
private final static boolean isDalvik = System.getProperty("java.vm.name").equals("Dalvik");
|
|
private static void snooze(int ms) {
|
try {
|
Thread.sleep(ms);
|
} catch (InterruptedException ie) {
|
System.out.println("Snooze: " + ie.getMessage());
|
}
|
}
|
|
public static WeakReference<FinalizerTest> makeRef() {
|
FinalizerTest ft = new FinalizerTest("wahoo");
|
WeakReference<FinalizerTest> ref = new WeakReference<FinalizerTest>(ft);
|
ft = null;
|
return ref;
|
}
|
|
public static String wimpString(final WeakReference<FinalizerTest> wimp) {
|
/*
|
* Do the work in another thread, so there is no danger of a
|
* conservative reference to ft leaking onto the main thread's
|
* stack.
|
*/
|
|
final String[] s = new String[1];
|
Thread t = new Thread() {
|
public void run() {
|
FinalizerTest ref = wimp.get();
|
if (ref != null) {
|
s[0] = ref.toString();
|
}
|
}
|
};
|
|
t.start();
|
|
try {
|
t.join();
|
} catch (InterruptedException ie) {
|
throw new RuntimeException(ie);
|
}
|
|
return s[0];
|
}
|
|
public static void main(String[] args) {
|
WeakReference<FinalizerTest> wimp = makeRef();
|
// Reference ft so we are sure the WeakReference cannot be cleared.
|
// Note: This is very fragile. It was previously in a helper function but that
|
// doesn't work for JIT-on-first-use with --gcstress where the object would be
|
// collected when JIT internally allocates an array. Also adding a scope around
|
// the keepLive lifetime somehow keeps a non-null `keepLive` around and makes
|
// the test fail (even when keeping the `null` assignment). b/76454261
|
FinalizerTest keepLive = wimp.get();
|
System.out.println("wimp: " + wimpString(wimp));
|
Reference.reachabilityFence(keepLive);
|
keepLive = null; // Clear the reference.
|
|
/* this will try to collect and finalize ft */
|
System.out.println("gc");
|
Runtime.getRuntime().gc();
|
|
System.out.println("wimp: " + wimpString(wimp));
|
System.out.println("finalize");
|
System.runFinalization();
|
System.out.println("wimp: " + wimpString(wimp));
|
|
System.out.println("sleep");
|
snooze(1000);
|
|
System.out.println("reborn: " + FinalizerTest.mReborn);
|
System.out.println("wimp: " + wimpString(wimp));
|
System.out.println("reset reborn");
|
Runtime.getRuntime().gc();
|
FinalizerTest.mReborn = FinalizerTest.mNothing;
|
System.out.println("gc + finalize");
|
System.gc();
|
System.runFinalization();
|
|
System.out.println("sleep");
|
snooze(1000);
|
|
System.out.println("reborn: " + FinalizerTest.mReborn);
|
System.out.println("wimp: " + wimpString(wimp));
|
// Test runFinalization with multiple objects.
|
runFinalizationTest();
|
}
|
|
static class FinalizeCounter {
|
public static final int maxCount = 1024;
|
public static boolean finalized[] = new boolean[maxCount];
|
private static Object finalizeLock = new Object();
|
private static volatile int finalizeCount = 0;
|
private int index;
|
static int getCount() {
|
return finalizeCount;
|
}
|
static void printNonFinalized() {
|
for (int i = 0; i < maxCount; ++i) {
|
if (!FinalizeCounter.finalized[i]) {
|
System.out.println("Element " + i + " was not finalized");
|
}
|
}
|
}
|
FinalizeCounter(int index) {
|
this.index = index;
|
}
|
protected void finalize() {
|
synchronized(finalizeLock) {
|
++finalizeCount;
|
finalized[index] = true;
|
}
|
}
|
}
|
|
private static void allocFinalizableObjects(int count) {
|
Object[] objs = new Object[count];
|
for (int i = 0; i < count; ++i) {
|
objs[i] = new FinalizeCounter(i);
|
}
|
}
|
|
private static void runFinalizationTest() {
|
allocFinalizableObjects(FinalizeCounter.maxCount);
|
Runtime.getRuntime().gc();
|
System.runFinalization();
|
if (FinalizeCounter.getCount() != FinalizeCounter.maxCount) {
|
if (isDalvik) {
|
// runFinalization is "expend effort", only ART makes a strong effort all finalizers ran.
|
System.out.println("Finalized " + FinalizeCounter.getCount() + " / " + FinalizeCounter.maxCount);
|
// Print out all the finalized elements.
|
FinalizeCounter.printNonFinalized();
|
}
|
// Try to sleep for a couple seconds to see if the objects became finalized after.
|
try {
|
java.lang.Thread.sleep(2000);
|
} catch (InterruptedException e) {
|
throw new AssertionError(e);
|
}
|
}
|
System.out.println("After sleep finalized " + FinalizeCounter.getCount() + " / " + FinalizeCounter.maxCount);
|
FinalizeCounter.printNonFinalized();
|
}
|
|
public static class FinalizerTest {
|
public static FinalizerTest mNothing = new FinalizerTest("nothing");
|
public static FinalizerTest mReborn = mNothing;
|
|
private final String message;
|
private boolean finalized = false;
|
|
public FinalizerTest(String message) {
|
this.message = message;
|
}
|
|
public String toString() {
|
return "[FinalizerTest message=" + message +
|
", finalized=" + finalized + "]";
|
}
|
|
protected void finalize() {
|
finalized = true;
|
mReborn = this;
|
}
|
}
|
}
|