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