xref: /aosp_15_r20/art/test/2043-reference-pauses/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2022 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 java.lang.ref.Reference;
18*795d594fSAndroid Build Coastguard Worker import java.lang.ref.WeakReference;
19*795d594fSAndroid Build Coastguard Worker import java.lang.ref.SoftReference;
20*795d594fSAndroid Build Coastguard Worker import java.math.BigInteger;
21*795d594fSAndroid Build Coastguard Worker import java.util.ArrayList;
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker /**
24*795d594fSAndroid Build Coastguard Worker  * Basic test of WeakReferences with large amounts of memory that's only reachable through
25*795d594fSAndroid Build Coastguard Worker  * finalizers. Also makes sure that finalizer-reachable data is not collected.
26*795d594fSAndroid Build Coastguard Worker  * Can easily be modified to time Reference.get() blocking.
27*795d594fSAndroid Build Coastguard Worker  */
28*795d594fSAndroid Build Coastguard Worker public class Main {
29*795d594fSAndroid Build Coastguard Worker     static final boolean PRINT_TIMES = false;  // true will cause benchmark failure.
30*795d594fSAndroid Build Coastguard Worker     // Data structures repeatedly allocated in background to trigger GC.
31*795d594fSAndroid Build Coastguard Worker     // Size of finalizer reachable trees.
32*795d594fSAndroid Build Coastguard Worker     static final int TREE_HEIGHT = 15;  // Trees contain 2^TREE_HEIGHT -1 allocated objects.
33*795d594fSAndroid Build Coastguard Worker     // Number of finalizable tree-owning objects that exist at one point.
34*795d594fSAndroid Build Coastguard Worker     static final int N_RESURRECTING_OBJECTS = 10;
35*795d594fSAndroid Build Coastguard Worker     // Number of short-lived, not finalizer-reachable, objects allocated between trees.
36*795d594fSAndroid Build Coastguard Worker     static final int N_PLAIN_OBJECTS = 20_000;
37*795d594fSAndroid Build Coastguard Worker     // Number of SoftReferences to CBTs we allocate.
38*795d594fSAndroid Build Coastguard Worker     static final int N_SOFTREFS = 10;
39*795d594fSAndroid Build Coastguard Worker 
40*795d594fSAndroid Build Coastguard Worker     static final boolean BACKGROUND_GC_THREAD = true;
41*795d594fSAndroid Build Coastguard Worker     static final int NBATCHES = 10;
42*795d594fSAndroid Build Coastguard Worker     static final int NREFS = PRINT_TIMES ? 1_000_000 : 300_000;  // Multiple of NBATCHES.
43*795d594fSAndroid Build Coastguard Worker     static final int REFS_PER_BATCH = NREFS / NBATCHES;
44*795d594fSAndroid Build Coastguard Worker 
45*795d594fSAndroid Build Coastguard Worker     static volatile boolean pleaseStop = false;
46*795d594fSAndroid Build Coastguard Worker 
47*795d594fSAndroid Build Coastguard Worker     // Large array of WeakReferences filled and accessed by tests below.
48*795d594fSAndroid Build Coastguard Worker     ArrayList<WeakReference<Integer>> weakRefs = new ArrayList<>(NREFS);
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker     /**
51*795d594fSAndroid Build Coastguard Worker      * Complete binary tree data structure. make(n) takes O(2^n) space.
52*795d594fSAndroid Build Coastguard Worker      */
53*795d594fSAndroid Build Coastguard Worker     static class CBT {
54*795d594fSAndroid Build Coastguard Worker         CBT left;
55*795d594fSAndroid Build Coastguard Worker         CBT right;
CBT(CBT l, CBT r)56*795d594fSAndroid Build Coastguard Worker         CBT(CBT l, CBT r) {
57*795d594fSAndroid Build Coastguard Worker             left = l;
58*795d594fSAndroid Build Coastguard Worker             right = r;
59*795d594fSAndroid Build Coastguard Worker         }
make(int n)60*795d594fSAndroid Build Coastguard Worker         static CBT make(int n) {
61*795d594fSAndroid Build Coastguard Worker             if (n == 0) {
62*795d594fSAndroid Build Coastguard Worker                 return null;
63*795d594fSAndroid Build Coastguard Worker             }
64*795d594fSAndroid Build Coastguard Worker             return new CBT(make(n - 1), make(n - 1));
65*795d594fSAndroid Build Coastguard Worker         }
66*795d594fSAndroid Build Coastguard Worker         /**
67*795d594fSAndroid Build Coastguard Worker          * Check that path described by bit-vector path has the correct length.
68*795d594fSAndroid Build Coastguard Worker          */
check(int n, int path)69*795d594fSAndroid Build Coastguard Worker         void check(int n, int path) {
70*795d594fSAndroid Build Coastguard Worker             CBT current = this;
71*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < n; i++, path = path >>> 1) {
72*795d594fSAndroid Build Coastguard Worker                 // Unexpectedly short paths result in NPE.
73*795d594fSAndroid Build Coastguard Worker                 if ((path & 1) == 0) {
74*795d594fSAndroid Build Coastguard Worker                     current = current.left;
75*795d594fSAndroid Build Coastguard Worker                 } else {
76*795d594fSAndroid Build Coastguard Worker                     current = current.right;
77*795d594fSAndroid Build Coastguard Worker                 }
78*795d594fSAndroid Build Coastguard Worker             }
79*795d594fSAndroid Build Coastguard Worker             if (current != null) {
80*795d594fSAndroid Build Coastguard Worker                 System.out.println("Complete binary tree path too long");
81*795d594fSAndroid Build Coastguard Worker             }
82*795d594fSAndroid Build Coastguard Worker         }
83*795d594fSAndroid Build Coastguard Worker     }
84*795d594fSAndroid Build Coastguard Worker 
85*795d594fSAndroid Build Coastguard Worker 
86*795d594fSAndroid Build Coastguard Worker     /**
87*795d594fSAndroid Build Coastguard Worker      * A finalizable object that refers to O(2^TREE_HEIGHT) otherwise unreachable memory.
88*795d594fSAndroid Build Coastguard Worker      * When finalized, it creates a new identical object, making sure that one always stays
89*795d594fSAndroid Build Coastguard Worker      * around.
90*795d594fSAndroid Build Coastguard Worker      */
91*795d594fSAndroid Build Coastguard Worker     static class ResurrectingObject {
92*795d594fSAndroid Build Coastguard Worker         CBT stuff;
ResurrectingObject()93*795d594fSAndroid Build Coastguard Worker         ResurrectingObject() {
94*795d594fSAndroid Build Coastguard Worker             stuff = CBT.make(TREE_HEIGHT);
95*795d594fSAndroid Build Coastguard Worker         }
96*795d594fSAndroid Build Coastguard Worker         static ResurrectingObject a[] = new ResurrectingObject[2];
97*795d594fSAndroid Build Coastguard Worker         static int i = 0;
allocOne()98*795d594fSAndroid Build Coastguard Worker         static synchronized void allocOne() {
99*795d594fSAndroid Build Coastguard Worker             a[(++i) % 2] = new ResurrectingObject();
100*795d594fSAndroid Build Coastguard Worker             // Check the previous one to make it hard to optimize anything out.
101*795d594fSAndroid Build Coastguard Worker             if (i > 1) {
102*795d594fSAndroid Build Coastguard Worker                 a[(i + 1) % 2].stuff.check(TREE_HEIGHT, i /* weirdly interpreted as path */);
103*795d594fSAndroid Build Coastguard Worker             }
104*795d594fSAndroid Build Coastguard Worker         }
finalize()105*795d594fSAndroid Build Coastguard Worker         protected void finalize() {
106*795d594fSAndroid Build Coastguard Worker             stuff.check(TREE_HEIGHT, 42 /* Some path descriptor */);
107*795d594fSAndroid Build Coastguard Worker             // Allocate a new one to replace this one.
108*795d594fSAndroid Build Coastguard Worker             allocOne();
109*795d594fSAndroid Build Coastguard Worker         }
110*795d594fSAndroid Build Coastguard Worker     }
111*795d594fSAndroid Build Coastguard Worker 
fillWeakRefs()112*795d594fSAndroid Build Coastguard Worker     void fillWeakRefs() {
113*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < NREFS; ++i) {
114*795d594fSAndroid Build Coastguard Worker              weakRefs.add(null);
115*795d594fSAndroid Build Coastguard Worker         }
116*795d594fSAndroid Build Coastguard Worker     }
117*795d594fSAndroid Build Coastguard Worker 
118*795d594fSAndroid Build Coastguard Worker     /*
119*795d594fSAndroid Build Coastguard Worker      * Return maximum observed time in nanos to dereference a WeakReference to an unreachable
120*795d594fSAndroid Build Coastguard Worker      * object. weakRefs is presumed to be pre-filled to have the correct size.
121*795d594fSAndroid Build Coastguard Worker      */
timeUnreachableInner()122*795d594fSAndroid Build Coastguard Worker     long timeUnreachableInner() {
123*795d594fSAndroid Build Coastguard Worker         long maxNanos = 0;
124*795d594fSAndroid Build Coastguard Worker         // Fill weakRefs with WeakReferences to unreachable integers, a batch at a time.
125*795d594fSAndroid Build Coastguard Worker         // Then time and test .get() calls on carefully sampled array entries, some of which
126*795d594fSAndroid Build Coastguard Worker         // will have been cleared.
127*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < NBATCHES; ++i) {
128*795d594fSAndroid Build Coastguard Worker             for (int j = 0; j < REFS_PER_BATCH; ++j) {
129*795d594fSAndroid Build Coastguard Worker                 weakRefs.set(i * REFS_PER_BATCH + j,
130*795d594fSAndroid Build Coastguard Worker                         new WeakReference(new Integer(i * REFS_PER_BATCH + j)));
131*795d594fSAndroid Build Coastguard Worker             }
132*795d594fSAndroid Build Coastguard Worker             try {
133*795d594fSAndroid Build Coastguard Worker                 Thread.sleep(50);
134*795d594fSAndroid Build Coastguard Worker             } catch (InterruptedException e) {
135*795d594fSAndroid Build Coastguard Worker                 System.out.println("Unexpected exception");
136*795d594fSAndroid Build Coastguard Worker             }
137*795d594fSAndroid Build Coastguard Worker             // Iterate over the filled-in section of weakRefs, but look only at a subset of the
138*795d594fSAndroid Build Coastguard Worker             // elements, making sure the subsets for different top-level iterations are disjoint.
139*795d594fSAndroid Build Coastguard Worker             // Otherwise the get() calls here will extend the lifetimes of the referents, and we
140*795d594fSAndroid Build Coastguard Worker             // may never see any cleared WeakReferences.
141*795d594fSAndroid Build Coastguard Worker             for (int j = (i + 1) * REFS_PER_BATCH - i - 1; j >= 0; j -= NBATCHES) {
142*795d594fSAndroid Build Coastguard Worker                 WeakReference<Integer> wr = weakRefs.get(j);
143*795d594fSAndroid Build Coastguard Worker                 if (wr != null) {
144*795d594fSAndroid Build Coastguard Worker                     long startNanos = System.nanoTime();
145*795d594fSAndroid Build Coastguard Worker                     Integer referent = wr.get();
146*795d594fSAndroid Build Coastguard Worker                     long totalNanos = System.nanoTime() - startNanos;
147*795d594fSAndroid Build Coastguard Worker                     if (referent == null) {
148*795d594fSAndroid Build Coastguard Worker                         // Optimization to reduce max space use and scanning time.
149*795d594fSAndroid Build Coastguard Worker                         weakRefs.set(j, null);
150*795d594fSAndroid Build Coastguard Worker                     }
151*795d594fSAndroid Build Coastguard Worker                     maxNanos = Math.max(maxNanos, totalNanos);
152*795d594fSAndroid Build Coastguard Worker                     if (referent != null && referent.intValue() != j) {
153*795d594fSAndroid Build Coastguard Worker                         System.out.println("Unexpected referent; expected " + j + " got "
154*795d594fSAndroid Build Coastguard Worker                                 + referent.intValue());
155*795d594fSAndroid Build Coastguard Worker                     }
156*795d594fSAndroid Build Coastguard Worker                 }
157*795d594fSAndroid Build Coastguard Worker             }
158*795d594fSAndroid Build Coastguard Worker         }
159*795d594fSAndroid Build Coastguard Worker         return maxNanos;
160*795d594fSAndroid Build Coastguard Worker     }
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker     /*
163*795d594fSAndroid Build Coastguard Worker      * Wrapper for the above that also checks that references were reclaimed.
164*795d594fSAndroid Build Coastguard Worker      * We do this separately to make sure any stack references from the core of the
165*795d594fSAndroid Build Coastguard Worker      * test are gone. Empirically, we otherwise sometimes see the zeroth WeakReference
166*795d594fSAndroid Build Coastguard Worker      * not reclaimed.
167*795d594fSAndroid Build Coastguard Worker      */
timeUnreachable()168*795d594fSAndroid Build Coastguard Worker     long timeUnreachable() {
169*795d594fSAndroid Build Coastguard Worker         long maxNanos = timeUnreachableInner();
170*795d594fSAndroid Build Coastguard Worker         Runtime.getRuntime().gc();
171*795d594fSAndroid Build Coastguard Worker         System.runFinalization();  // Presumed to wait for reference clearing.
172*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < NREFS; ++i) {
173*795d594fSAndroid Build Coastguard Worker             if (weakRefs.get(i) != null && weakRefs.get(i).get() != null) {
174*795d594fSAndroid Build Coastguard Worker                 System.out.println("WeakReference to " + i + " wasn't cleared");
175*795d594fSAndroid Build Coastguard Worker             }
176*795d594fSAndroid Build Coastguard Worker         }
177*795d594fSAndroid Build Coastguard Worker         return maxNanos;
178*795d594fSAndroid Build Coastguard Worker     }
179*795d594fSAndroid Build Coastguard Worker 
180*795d594fSAndroid Build Coastguard Worker     /**
181*795d594fSAndroid Build Coastguard Worker      * Return maximum observed time in nanos to dereference a WeakReference to a reachable
182*795d594fSAndroid Build Coastguard Worker      * object. Overwrites weakRefs, which is presumed to have NREFS entries already.
183*795d594fSAndroid Build Coastguard Worker     */
timeReachable()184*795d594fSAndroid Build Coastguard Worker     long timeReachable() {
185*795d594fSAndroid Build Coastguard Worker         long maxNanos = 0;
186*795d594fSAndroid Build Coastguard Worker         // Similar to the above, but we use WeakReferences to otherwise reachable objects,
187*795d594fSAndroid Build Coastguard Worker         // which should thus not get cleared.
188*795d594fSAndroid Build Coastguard Worker         Integer[] strongRefs = new Integer[NREFS];
189*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < NBATCHES; ++i) {
190*795d594fSAndroid Build Coastguard Worker             for (int j = i * REFS_PER_BATCH; j < (i + 1) * REFS_PER_BATCH; ++j) {
191*795d594fSAndroid Build Coastguard Worker                 Integer newObj = new Integer(j);
192*795d594fSAndroid Build Coastguard Worker                 strongRefs[j] = newObj;
193*795d594fSAndroid Build Coastguard Worker                 weakRefs.set(j, new WeakReference(newObj));
194*795d594fSAndroid Build Coastguard Worker             }
195*795d594fSAndroid Build Coastguard Worker             for (int j = (i + 1) * REFS_PER_BATCH - 1; j >= 0; --j) {
196*795d594fSAndroid Build Coastguard Worker                 WeakReference<Integer> wr = weakRefs.get(j);
197*795d594fSAndroid Build Coastguard Worker                 long startNanos = System.nanoTime();
198*795d594fSAndroid Build Coastguard Worker                 Integer referent = wr.get();
199*795d594fSAndroid Build Coastguard Worker                 long totalNanos = System.nanoTime() - startNanos;
200*795d594fSAndroid Build Coastguard Worker                 maxNanos = Math.max(maxNanos, totalNanos);
201*795d594fSAndroid Build Coastguard Worker                 if (referent == null) {
202*795d594fSAndroid Build Coastguard Worker                     System.out.println("Unexpectedly cleared referent at " + j);
203*795d594fSAndroid Build Coastguard Worker                 } else if (referent.intValue() != j) {
204*795d594fSAndroid Build Coastguard Worker                     System.out.println("Unexpected reachable referent; expected " + j + " got "
205*795d594fSAndroid Build Coastguard Worker                             + referent.intValue());
206*795d594fSAndroid Build Coastguard Worker                 }
207*795d594fSAndroid Build Coastguard Worker             }
208*795d594fSAndroid Build Coastguard Worker         }
209*795d594fSAndroid Build Coastguard Worker         Reference.reachabilityFence(strongRefs);
210*795d594fSAndroid Build Coastguard Worker         return maxNanos;
211*795d594fSAndroid Build Coastguard Worker     }
212*795d594fSAndroid Build Coastguard Worker 
runTest()213*795d594fSAndroid Build Coastguard Worker     void runTest() {
214*795d594fSAndroid Build Coastguard Worker         System.out.println("Starting");
215*795d594fSAndroid Build Coastguard Worker         fillWeakRefs();
216*795d594fSAndroid Build Coastguard Worker         long unreachableNanos = timeUnreachable();
217*795d594fSAndroid Build Coastguard Worker         if (PRINT_TIMES) {
218*795d594fSAndroid Build Coastguard Worker             System.out.println("Finished timeUnrechable()");
219*795d594fSAndroid Build Coastguard Worker         }
220*795d594fSAndroid Build Coastguard Worker         long reachableNanos = timeReachable();
221*795d594fSAndroid Build Coastguard Worker         String unreachableMillis =
222*795d594fSAndroid Build Coastguard Worker                 String. format("%,.3f", ((double) unreachableNanos) / 1_000_000);
223*795d594fSAndroid Build Coastguard Worker         String reachableMillis =
224*795d594fSAndroid Build Coastguard Worker                 String. format("%,.3f", ((double) reachableNanos) / 1_000_000);
225*795d594fSAndroid Build Coastguard Worker         if (PRINT_TIMES) {
226*795d594fSAndroid Build Coastguard Worker             System.out.println(
227*795d594fSAndroid Build Coastguard Worker                     "Max time for WeakReference.get (unreachable): " + unreachableMillis);
228*795d594fSAndroid Build Coastguard Worker             System.out.println(
229*795d594fSAndroid Build Coastguard Worker                     "Max time for WeakReference.get (reachable): " + reachableMillis);
230*795d594fSAndroid Build Coastguard Worker         }
231*795d594fSAndroid Build Coastguard Worker         // Only report extremely egregious pauses to avoid spurious failures.
232*795d594fSAndroid Build Coastguard Worker         if (unreachableNanos > 10_000_000_000L) {
233*795d594fSAndroid Build Coastguard Worker             System.out.println("WeakReference.get (unreachable) time unreasonably long");
234*795d594fSAndroid Build Coastguard Worker         }
235*795d594fSAndroid Build Coastguard Worker         if (reachableNanos > 10_000_000_000L) {
236*795d594fSAndroid Build Coastguard Worker             System.out.println("WeakReference.get (reachable) time unreasonably long");
237*795d594fSAndroid Build Coastguard Worker         }
238*795d594fSAndroid Build Coastguard Worker     }
239*795d594fSAndroid Build Coastguard Worker 
240*795d594fSAndroid Build Coastguard Worker     /**
241*795d594fSAndroid Build Coastguard Worker      * Allocate and GC a lot, while keeping significant amounts of finalizer and
242*795d594fSAndroid Build Coastguard Worker      * SoftReference-reachable memory around.
243*795d594fSAndroid Build Coastguard Worker      */
244*795d594fSAndroid Build Coastguard Worker     static Runnable allocFinalizable = new Runnable() {
245*795d594fSAndroid Build Coastguard Worker         public void run() {
246*795d594fSAndroid Build Coastguard Worker             // Allocate and drop some finalizable objects that take a long time
247*795d594fSAndroid Build Coastguard Worker             // to mark. Designed to be hard to optimize away. Each of these objects will
248*795d594fSAndroid Build Coastguard Worker             // build a new one in its finalizer before really going away.
249*795d594fSAndroid Build Coastguard Worker             ArrayList<SoftReference<CBT>> softRefs = new ArrayList<>(N_SOFTREFS);
250*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < N_SOFTREFS; ++i) {
251*795d594fSAndroid Build Coastguard Worker                 // These should not normally get reclaimed, since we shouldn't run out of
252*795d594fSAndroid Build Coastguard Worker                 // memory. They do increase tracing time.
253*795d594fSAndroid Build Coastguard Worker                 softRefs.add(new SoftReference(CBT.make(TREE_HEIGHT)));
254*795d594fSAndroid Build Coastguard Worker             }
255*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < N_RESURRECTING_OBJECTS; ++i) {
256*795d594fSAndroid Build Coastguard Worker                 ResurrectingObject.allocOne();
257*795d594fSAndroid Build Coastguard Worker             }
258*795d594fSAndroid Build Coastguard Worker             BigInteger counter = BigInteger.ZERO;
259*795d594fSAndroid Build Coastguard Worker             for (int i = 1; !pleaseStop; ++i) {
260*795d594fSAndroid Build Coastguard Worker                 // Allocate a lot of short-lived objects, using BigIntegers to minimize the chance
261*795d594fSAndroid Build Coastguard Worker                 // of the allocation getting optimized out. This makes things slightly more
262*795d594fSAndroid Build Coastguard Worker                 // realistic, since not all objects will be finalizer reachable.
263*795d594fSAndroid Build Coastguard Worker                 for (int j = 0; j < N_PLAIN_OBJECTS / 2; ++j) {
264*795d594fSAndroid Build Coastguard Worker                     counter = counter.add(BigInteger.TEN);
265*795d594fSAndroid Build Coastguard Worker                 }
266*795d594fSAndroid Build Coastguard Worker                 // Look at counter to reduce chance of optimizing out the allocation.
267*795d594fSAndroid Build Coastguard Worker                 if (counter.longValue() % 10 != 0) {
268*795d594fSAndroid Build Coastguard Worker                     System.out.println("Bad allocFinalizable counter value: " + counter);
269*795d594fSAndroid Build Coastguard Worker                 }
270*795d594fSAndroid Build Coastguard Worker                 // Explicitly collect here, mostly to prevent heap growth. Otherwise we get
271*795d594fSAndroid Build Coastguard Worker                 // ahead of the GC and eventually block on it.
272*795d594fSAndroid Build Coastguard Worker                 Runtime.getRuntime().gc();
273*795d594fSAndroid Build Coastguard Worker                 if (PRINT_TIMES && i % 100 == 0) {
274*795d594fSAndroid Build Coastguard Worker                     System.out.println("Collected " + i + " times");
275*795d594fSAndroid Build Coastguard Worker                 }
276*795d594fSAndroid Build Coastguard Worker             }
277*795d594fSAndroid Build Coastguard Worker             // To be safe, access softRefs.
278*795d594fSAndroid Build Coastguard Worker             final CBT sample = softRefs.get(N_SOFTREFS / 2).get();
279*795d594fSAndroid Build Coastguard Worker             if (sample != null) {
280*795d594fSAndroid Build Coastguard Worker               sample.check(TREE_HEIGHT, 47 /* some path descriptor */);
281*795d594fSAndroid Build Coastguard Worker             }
282*795d594fSAndroid Build Coastguard Worker         }
283*795d594fSAndroid Build Coastguard Worker     };
284*795d594fSAndroid Build Coastguard Worker 
main(String[] args)285*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
286*795d594fSAndroid Build Coastguard Worker         Main theTest = new Main();
287*795d594fSAndroid Build Coastguard Worker         Thread allocThread = null;
288*795d594fSAndroid Build Coastguard Worker         if (BACKGROUND_GC_THREAD) {
289*795d594fSAndroid Build Coastguard Worker             allocThread = new Thread(allocFinalizable);
290*795d594fSAndroid Build Coastguard Worker             allocThread.setDaemon(true);  // Terminate if main thread dies.
291*795d594fSAndroid Build Coastguard Worker             allocThread.start();
292*795d594fSAndroid Build Coastguard Worker         }
293*795d594fSAndroid Build Coastguard Worker         theTest.runTest();
294*795d594fSAndroid Build Coastguard Worker         if (BACKGROUND_GC_THREAD) {
295*795d594fSAndroid Build Coastguard Worker             pleaseStop = true;
296*795d594fSAndroid Build Coastguard Worker             allocThread.join();
297*795d594fSAndroid Build Coastguard Worker         }
298*795d594fSAndroid Build Coastguard Worker         System.out.println("Finished");
299*795d594fSAndroid Build Coastguard Worker     }
300*795d594fSAndroid Build Coastguard Worker }
301