xref: /aosp_15_r20/art/test/2042-reference-processing/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.PhantomReference;
18*795d594fSAndroid Build Coastguard Worker import java.lang.ref.Reference;
19*795d594fSAndroid Build Coastguard Worker import java.lang.ref.ReferenceQueue;
20*795d594fSAndroid Build Coastguard Worker import java.lang.ref.WeakReference;
21*795d594fSAndroid Build Coastguard Worker import java.math.BigInteger;
22*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ArrayBlockingQueue;
23*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.atomic.AtomicInteger;
24*795d594fSAndroid Build Coastguard Worker import java.util.concurrent.ConcurrentHashMap;
25*795d594fSAndroid Build Coastguard Worker import java.util.TreeMap;
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker /**
28*795d594fSAndroid Build Coastguard Worker  * Test that objects get finalized and their references cleared in the right order.
29*795d594fSAndroid Build Coastguard Worker  *
30*795d594fSAndroid Build Coastguard Worker  * We maintain a list of nominally MAX_LIVE_OBJS numbered finalizable objects.
31*795d594fSAndroid Build Coastguard Worker  * We then alternately drop the last 50, and add 50 more. When we see an object finalized
32*795d594fSAndroid Build Coastguard Worker  * or its reference cleared, we make sure that the preceding objects in its group of 50
33*795d594fSAndroid Build Coastguard Worker  * have also had their references cleared. We also perform a number of other more
34*795d594fSAndroid Build Coastguard Worker  * straightforward checks, such as ensuring that all references are eventually cleared,
35*795d594fSAndroid Build Coastguard Worker  * and all objects are finalized.
36*795d594fSAndroid Build Coastguard Worker  */
37*795d594fSAndroid Build Coastguard Worker public class Main {
38*795d594fSAndroid Build Coastguard Worker     // TODO(b/216481630) Enable CHECK_PHANTOM_REFS. This currently occasionally reports a few
39*795d594fSAndroid Build Coastguard Worker     // PhantomReferences as not enqueued. If this report is correct, this needs to be tracked
40*795d594fSAndroid Build Coastguard Worker     // down and fixed.
41*795d594fSAndroid Build Coastguard Worker     static final boolean CHECK_PHANTOM_REFS = false;
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker     static final int MAX_LIVE_OBJS = 150;
44*795d594fSAndroid Build Coastguard Worker     static final int DROP_OBJS = 50;  // Number of linked objects dropped in each batch.
45*795d594fSAndroid Build Coastguard Worker     static final int MIN_LIVE_OBJS = MAX_LIVE_OBJS - DROP_OBJS;
46*795d594fSAndroid Build Coastguard Worker     static final int TOTAL_OBJS = 200_000;  // Allocate this many finalizable objects in total.
47*795d594fSAndroid Build Coastguard Worker     static final boolean REPORT_DROPS = false;
48*795d594fSAndroid Build Coastguard Worker     static volatile boolean pleaseStop;
49*795d594fSAndroid Build Coastguard Worker 
50*795d594fSAndroid Build Coastguard Worker     AtomicInteger totalFinalized = new AtomicInteger(0);
51*795d594fSAndroid Build Coastguard Worker     int maxDropped = 0;
52*795d594fSAndroid Build Coastguard Worker     int liveObjects = 0;
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker     // Number of next finalizable object to be allocated.
55*795d594fSAndroid Build Coastguard Worker     int nextAllocated = 0;
56*795d594fSAndroid Build Coastguard Worker 
57*795d594fSAndroid Build Coastguard Worker     // List of finalizable objects in descending order. We add to the front and drop
58*795d594fSAndroid Build Coastguard Worker     // from the rear.
59*795d594fSAndroid Build Coastguard Worker     FinalizableObject listHead;
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker     // A possibly incomplete list of FinalizableObject indices that were finalized, but
62*795d594fSAndroid Build Coastguard Worker     // have yet to be checked for consistency with reference processing.
63*795d594fSAndroid Build Coastguard Worker     ArrayBlockingQueue<Integer> finalized = new ArrayBlockingQueue<>(20_000);
64*795d594fSAndroid Build Coastguard Worker 
65*795d594fSAndroid Build Coastguard Worker     // Maps from object number to Reference; Cleared references are deleted when queues are
66*795d594fSAndroid Build Coastguard Worker     // processed.
67*795d594fSAndroid Build Coastguard Worker     TreeMap<Integer, MyWeakReference> weakRefs = new TreeMap<>();
68*795d594fSAndroid Build Coastguard Worker     ConcurrentHashMap<Integer, MyPhantomReference> phantomRefs = new ConcurrentHashMap<>();
69*795d594fSAndroid Build Coastguard Worker 
70*795d594fSAndroid Build Coastguard Worker     class FinalizableObject {
71*795d594fSAndroid Build Coastguard Worker         int n;
72*795d594fSAndroid Build Coastguard Worker         FinalizableObject next;
FinalizableObject(int num, FinalizableObject nextObj)73*795d594fSAndroid Build Coastguard Worker         FinalizableObject(int num, FinalizableObject nextObj) {
74*795d594fSAndroid Build Coastguard Worker             n = num;
75*795d594fSAndroid Build Coastguard Worker             next = nextObj;
76*795d594fSAndroid Build Coastguard Worker         }
finalize()77*795d594fSAndroid Build Coastguard Worker         protected void finalize() {
78*795d594fSAndroid Build Coastguard Worker             if (!inPhantomRefs(n)) {
79*795d594fSAndroid Build Coastguard Worker                 System.out.println("PhantomRef enqueued before finalizer ran");
80*795d594fSAndroid Build Coastguard Worker             }
81*795d594fSAndroid Build Coastguard Worker             totalFinalized.incrementAndGet();
82*795d594fSAndroid Build Coastguard Worker             if (!finalized.offer(n) && REPORT_DROPS) {
83*795d594fSAndroid Build Coastguard Worker                 System.out.println("Dropped finalization of " + n);
84*795d594fSAndroid Build Coastguard Worker             }
85*795d594fSAndroid Build Coastguard Worker         }
86*795d594fSAndroid Build Coastguard Worker     }
87*795d594fSAndroid Build Coastguard Worker     ReferenceQueue<FinalizableObject> refQueue = new ReferenceQueue<>();
88*795d594fSAndroid Build Coastguard Worker     class MyWeakReference extends WeakReference<FinalizableObject> {
89*795d594fSAndroid Build Coastguard Worker         int n;
MyWeakReference(FinalizableObject obj)90*795d594fSAndroid Build Coastguard Worker         MyWeakReference(FinalizableObject obj) {
91*795d594fSAndroid Build Coastguard Worker             super(obj, refQueue);
92*795d594fSAndroid Build Coastguard Worker             n = obj.n;
93*795d594fSAndroid Build Coastguard Worker         }
94*795d594fSAndroid Build Coastguard Worker     };
95*795d594fSAndroid Build Coastguard Worker     class MyPhantomReference extends PhantomReference<FinalizableObject> {
96*795d594fSAndroid Build Coastguard Worker         int n;
MyPhantomReference(FinalizableObject obj)97*795d594fSAndroid Build Coastguard Worker         MyPhantomReference(FinalizableObject obj) {
98*795d594fSAndroid Build Coastguard Worker             super(obj, refQueue);
99*795d594fSAndroid Build Coastguard Worker             n = obj.n;
100*795d594fSAndroid Build Coastguard Worker         }
101*795d594fSAndroid Build Coastguard Worker     }
inPhantomRefs(int n)102*795d594fSAndroid Build Coastguard Worker     boolean inPhantomRefs(int n) {
103*795d594fSAndroid Build Coastguard Worker         MyPhantomReference ref = phantomRefs.get(n);
104*795d594fSAndroid Build Coastguard Worker         if (ref == null) {
105*795d594fSAndroid Build Coastguard Worker             return false;
106*795d594fSAndroid Build Coastguard Worker         }
107*795d594fSAndroid Build Coastguard Worker         if (ref.n != n) {
108*795d594fSAndroid Build Coastguard Worker             System.out.println("phantomRef retrieval failed");
109*795d594fSAndroid Build Coastguard Worker         }
110*795d594fSAndroid Build Coastguard Worker         return true;
111*795d594fSAndroid Build Coastguard Worker     }
112*795d594fSAndroid Build Coastguard Worker 
CheckOKToClearWeak(int num)113*795d594fSAndroid Build Coastguard Worker     void CheckOKToClearWeak(int num) {
114*795d594fSAndroid Build Coastguard Worker         if (num > maxDropped) {
115*795d594fSAndroid Build Coastguard Worker             System.out.println("WeakRef to live object " + num + " was cleared/enqueued.");
116*795d594fSAndroid Build Coastguard Worker         }
117*795d594fSAndroid Build Coastguard Worker         int batchEnd = (num / DROP_OBJS + 1) * DROP_OBJS;
118*795d594fSAndroid Build Coastguard Worker         for (MyWeakReference wr : weakRefs.subMap(num + 1, batchEnd).values()) {
119*795d594fSAndroid Build Coastguard Worker             if (wr.n <= num || wr.n / DROP_OBJS != num / DROP_OBJS) {
120*795d594fSAndroid Build Coastguard Worker                 throw new AssertionError("MyWeakReference logic error!");
121*795d594fSAndroid Build Coastguard Worker             }
122*795d594fSAndroid Build Coastguard Worker             // wr referent was dropped in same batch and precedes it in list.
123*795d594fSAndroid Build Coastguard Worker             if (wr.get() != null) {
124*795d594fSAndroid Build Coastguard Worker                 // This violates the WeakReference spec, and can result in strong references
125*795d594fSAndroid Build Coastguard Worker                 // to objects that have been cleaned.
126*795d594fSAndroid Build Coastguard Worker                 System.out.println("WeakReference to " + wr.n
127*795d594fSAndroid Build Coastguard Worker                     + " was erroneously cleared after " + num);
128*795d594fSAndroid Build Coastguard Worker             }
129*795d594fSAndroid Build Coastguard Worker         }
130*795d594fSAndroid Build Coastguard Worker     }
131*795d594fSAndroid Build Coastguard Worker 
CheckOKToClearPhantom(int num)132*795d594fSAndroid Build Coastguard Worker     void CheckOKToClearPhantom(int num) {
133*795d594fSAndroid Build Coastguard Worker         if (num > maxDropped) {
134*795d594fSAndroid Build Coastguard Worker             System.out.println("PhantomRef to live object " + num + " was enqueued.");
135*795d594fSAndroid Build Coastguard Worker         }
136*795d594fSAndroid Build Coastguard Worker         MyWeakReference wr = weakRefs.get(num);
137*795d594fSAndroid Build Coastguard Worker         if (wr != null && wr.get() != null) {
138*795d594fSAndroid Build Coastguard Worker             System.out.println("PhantomRef cleared before WeakRef for " + num);
139*795d594fSAndroid Build Coastguard Worker         }
140*795d594fSAndroid Build Coastguard Worker     }
141*795d594fSAndroid Build Coastguard Worker 
emptyAndCheckQueues()142*795d594fSAndroid Build Coastguard Worker     void emptyAndCheckQueues() {
143*795d594fSAndroid Build Coastguard Worker         // Check recently finalized objects for consistency with cleared references.
144*795d594fSAndroid Build Coastguard Worker         while (true) {
145*795d594fSAndroid Build Coastguard Worker             Integer num = finalized.poll();
146*795d594fSAndroid Build Coastguard Worker             if (num == null) {
147*795d594fSAndroid Build Coastguard Worker                 break;
148*795d594fSAndroid Build Coastguard Worker             }
149*795d594fSAndroid Build Coastguard Worker             MyWeakReference wr = weakRefs.get(num);
150*795d594fSAndroid Build Coastguard Worker             if (wr != null) {
151*795d594fSAndroid Build Coastguard Worker                 if (wr.n != num) {
152*795d594fSAndroid Build Coastguard Worker                     System.out.println("Finalization logic error!");
153*795d594fSAndroid Build Coastguard Worker                 }
154*795d594fSAndroid Build Coastguard Worker                 if (wr.get() != null) {
155*795d594fSAndroid Build Coastguard Worker                     System.out.println("Finalizing object with uncleared reference");
156*795d594fSAndroid Build Coastguard Worker                 }
157*795d594fSAndroid Build Coastguard Worker             }
158*795d594fSAndroid Build Coastguard Worker             CheckOKToClearWeak(num);
159*795d594fSAndroid Build Coastguard Worker         }
160*795d594fSAndroid Build Coastguard Worker         // Check recently enqueued references for consistency.
161*795d594fSAndroid Build Coastguard Worker         while (true) {
162*795d594fSAndroid Build Coastguard Worker             Reference<FinalizableObject> ref = (Reference<FinalizableObject>) refQueue.poll();
163*795d594fSAndroid Build Coastguard Worker             if (ref == null) {
164*795d594fSAndroid Build Coastguard Worker                 break;
165*795d594fSAndroid Build Coastguard Worker             }
166*795d594fSAndroid Build Coastguard Worker             if (ref instanceof MyWeakReference) {
167*795d594fSAndroid Build Coastguard Worker                 MyWeakReference wr = (MyWeakReference) ref;
168*795d594fSAndroid Build Coastguard Worker                 if (wr.get() != null) {
169*795d594fSAndroid Build Coastguard Worker                     System.out.println("WeakRef " + wr.n + " enqueued but not cleared");
170*795d594fSAndroid Build Coastguard Worker                 }
171*795d594fSAndroid Build Coastguard Worker                 CheckOKToClearWeak(wr.n);
172*795d594fSAndroid Build Coastguard Worker                 if (weakRefs.remove(Integer.valueOf(wr.n)) != ref) {
173*795d594fSAndroid Build Coastguard Worker                     System.out.println("Missing WeakReference: " + wr.n);
174*795d594fSAndroid Build Coastguard Worker                 }
175*795d594fSAndroid Build Coastguard Worker             } else if (ref instanceof MyPhantomReference) {
176*795d594fSAndroid Build Coastguard Worker                 MyPhantomReference pr = (MyPhantomReference) ref;
177*795d594fSAndroid Build Coastguard Worker                 CheckOKToClearPhantom(pr.n);
178*795d594fSAndroid Build Coastguard Worker                 if (phantomRefs.remove(Integer.valueOf(pr.n)) != ref) {
179*795d594fSAndroid Build Coastguard Worker                     System.out.println("Missing PhantomReference: " + pr.n);
180*795d594fSAndroid Build Coastguard Worker                 }
181*795d594fSAndroid Build Coastguard Worker             } else {
182*795d594fSAndroid Build Coastguard Worker                 System.out.println("Found unrecognized reference in queue");
183*795d594fSAndroid Build Coastguard Worker             }
184*795d594fSAndroid Build Coastguard Worker         }
185*795d594fSAndroid Build Coastguard Worker     }
186*795d594fSAndroid Build Coastguard Worker 
187*795d594fSAndroid Build Coastguard Worker 
188*795d594fSAndroid Build Coastguard Worker     /**
189*795d594fSAndroid Build Coastguard Worker      * Add n objects to the head of the list. These will be assigned the next n consecutive
190*795d594fSAndroid Build Coastguard Worker      * numbers after the current head of the list.
191*795d594fSAndroid Build Coastguard Worker      */
addObjects(int n)192*795d594fSAndroid Build Coastguard Worker     void addObjects(int n) {
193*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < n; ++i) {
194*795d594fSAndroid Build Coastguard Worker             int me = nextAllocated++;
195*795d594fSAndroid Build Coastguard Worker             listHead = new FinalizableObject(me, listHead);
196*795d594fSAndroid Build Coastguard Worker             weakRefs.put(me, new MyWeakReference(listHead));
197*795d594fSAndroid Build Coastguard Worker             phantomRefs.put(me, new MyPhantomReference(listHead));
198*795d594fSAndroid Build Coastguard Worker         }
199*795d594fSAndroid Build Coastguard Worker         liveObjects += n;
200*795d594fSAndroid Build Coastguard Worker     }
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker     /**
203*795d594fSAndroid Build Coastguard Worker      * Drop n finalizable objects from the tail of the list. These are the lowest-numbered objects
204*795d594fSAndroid Build Coastguard Worker      * in the list.
205*795d594fSAndroid Build Coastguard Worker      */
dropObjects(int n)206*795d594fSAndroid Build Coastguard Worker     void dropObjects(int n) {
207*795d594fSAndroid Build Coastguard Worker         FinalizableObject list = listHead;
208*795d594fSAndroid Build Coastguard Worker         FinalizableObject last = null;
209*795d594fSAndroid Build Coastguard Worker         if (n > liveObjects) {
210*795d594fSAndroid Build Coastguard Worker             System.out.println("Removing too many elements");
211*795d594fSAndroid Build Coastguard Worker         }
212*795d594fSAndroid Build Coastguard Worker         if (liveObjects == n) {
213*795d594fSAndroid Build Coastguard Worker             maxDropped = list.n;
214*795d594fSAndroid Build Coastguard Worker             listHead = null;
215*795d594fSAndroid Build Coastguard Worker         } else {
216*795d594fSAndroid Build Coastguard Worker             final int skip = liveObjects - n;
217*795d594fSAndroid Build Coastguard Worker             for (int i = 0; i < skip; ++i) {
218*795d594fSAndroid Build Coastguard Worker                 last = list;
219*795d594fSAndroid Build Coastguard Worker                 list = list.next;
220*795d594fSAndroid Build Coastguard Worker             }
221*795d594fSAndroid Build Coastguard Worker             int expected = nextAllocated - skip - 1;
222*795d594fSAndroid Build Coastguard Worker             if (list.n != expected) {
223*795d594fSAndroid Build Coastguard Worker                 System.out.println("dropObjects found " + list.n + " but expected " + expected);
224*795d594fSAndroid Build Coastguard Worker             }
225*795d594fSAndroid Build Coastguard Worker             maxDropped = expected;
226*795d594fSAndroid Build Coastguard Worker             last.next = null;
227*795d594fSAndroid Build Coastguard Worker         }
228*795d594fSAndroid Build Coastguard Worker         liveObjects -= n;
229*795d594fSAndroid Build Coastguard Worker     }
230*795d594fSAndroid Build Coastguard Worker 
testLoop()231*795d594fSAndroid Build Coastguard Worker     void testLoop() {
232*795d594fSAndroid Build Coastguard Worker         System.out.println("Starting");
233*795d594fSAndroid Build Coastguard Worker         addObjects(MIN_LIVE_OBJS);
234*795d594fSAndroid Build Coastguard Worker         final int ITERS = (TOTAL_OBJS - MIN_LIVE_OBJS) / DROP_OBJS;
235*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < ITERS; ++i) {
236*795d594fSAndroid Build Coastguard Worker             addObjects(DROP_OBJS);
237*795d594fSAndroid Build Coastguard Worker             if (liveObjects != MAX_LIVE_OBJS) {
238*795d594fSAndroid Build Coastguard Worker                 System.out.println("Unexpected live object count");
239*795d594fSAndroid Build Coastguard Worker             }
240*795d594fSAndroid Build Coastguard Worker             dropObjects(DROP_OBJS);
241*795d594fSAndroid Build Coastguard Worker             if (i % 100 == 0) {
242*795d594fSAndroid Build Coastguard Worker               // Make sure we don't fall too far behind, otherwise we may run out of memory.
243*795d594fSAndroid Build Coastguard Worker               System.runFinalization();
244*795d594fSAndroid Build Coastguard Worker             }
245*795d594fSAndroid Build Coastguard Worker             emptyAndCheckQueues();
246*795d594fSAndroid Build Coastguard Worker         }
247*795d594fSAndroid Build Coastguard Worker         dropObjects(MIN_LIVE_OBJS);
248*795d594fSAndroid Build Coastguard Worker         if (liveObjects != 0 || listHead != null) {
249*795d594fSAndroid Build Coastguard Worker             System.out.println("Unexpected live objecs at end");
250*795d594fSAndroid Build Coastguard Worker         }
251*795d594fSAndroid Build Coastguard Worker         if (maxDropped != TOTAL_OBJS - 1) {
252*795d594fSAndroid Build Coastguard Worker             System.out.println("Unexpected dropped object count: " + maxDropped);
253*795d594fSAndroid Build Coastguard Worker         }
254*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < 2; ++i) {
255*795d594fSAndroid Build Coastguard Worker             Runtime.getRuntime().gc();
256*795d594fSAndroid Build Coastguard Worker             System.runFinalization();
257*795d594fSAndroid Build Coastguard Worker             emptyAndCheckQueues();
258*795d594fSAndroid Build Coastguard Worker         }
259*795d594fSAndroid Build Coastguard Worker         if (!weakRefs.isEmpty()) {
260*795d594fSAndroid Build Coastguard Worker             System.out.println("Weak Reference map nonempty size = " + weakRefs.size());
261*795d594fSAndroid Build Coastguard Worker         }
262*795d594fSAndroid Build Coastguard Worker         if (CHECK_PHANTOM_REFS && !phantomRefs.isEmpty()) {
263*795d594fSAndroid Build Coastguard Worker             try {
264*795d594fSAndroid Build Coastguard Worker                 Thread.sleep(500);
265*795d594fSAndroid Build Coastguard Worker             } catch (InterruptedException e) {
266*795d594fSAndroid Build Coastguard Worker                 System.out.println("Unexpected interrupt");
267*795d594fSAndroid Build Coastguard Worker             }
268*795d594fSAndroid Build Coastguard Worker             if (!phantomRefs.isEmpty()) {
269*795d594fSAndroid Build Coastguard Worker                 System.out.println("Phantom Reference map nonempty size = " + phantomRefs.size());
270*795d594fSAndroid Build Coastguard Worker                 System.out.print("First elements:");
271*795d594fSAndroid Build Coastguard Worker                 int i = 0;
272*795d594fSAndroid Build Coastguard Worker                 for (MyPhantomReference pr : phantomRefs.values()) {
273*795d594fSAndroid Build Coastguard Worker                     System.out.print(" " + pr.n);
274*795d594fSAndroid Build Coastguard Worker                     if (++i > 10) {
275*795d594fSAndroid Build Coastguard Worker                         break;
276*795d594fSAndroid Build Coastguard Worker                     }
277*795d594fSAndroid Build Coastguard Worker                 }
278*795d594fSAndroid Build Coastguard Worker                 System.out.println("");
279*795d594fSAndroid Build Coastguard Worker             }
280*795d594fSAndroid Build Coastguard Worker         }
281*795d594fSAndroid Build Coastguard Worker         if (totalFinalized.get() != TOTAL_OBJS) {
282*795d594fSAndroid Build Coastguard Worker             System.out.println("Finalized only " + totalFinalized + " objects");
283*795d594fSAndroid Build Coastguard Worker         }
284*795d594fSAndroid Build Coastguard Worker     }
285*795d594fSAndroid Build Coastguard Worker 
286*795d594fSAndroid Build Coastguard Worker     static Runnable causeGCs = new Runnable() {
287*795d594fSAndroid Build Coastguard Worker         public void run() {
288*795d594fSAndroid Build Coastguard Worker             // Allocate a lot.
289*795d594fSAndroid Build Coastguard Worker             BigInteger counter = BigInteger.ZERO;
290*795d594fSAndroid Build Coastguard Worker             while (!pleaseStop) {
291*795d594fSAndroid Build Coastguard Worker                 counter = counter.add(BigInteger.TEN);
292*795d594fSAndroid Build Coastguard Worker             }
293*795d594fSAndroid Build Coastguard Worker             // Look at counter to reduce chance of optimizing out the allocation.
294*795d594fSAndroid Build Coastguard Worker             if (counter.longValue() % 10 != 0) {
295*795d594fSAndroid Build Coastguard Worker                  System.out.println("Bad causeGCs counter value: " + counter);
296*795d594fSAndroid Build Coastguard Worker             }
297*795d594fSAndroid Build Coastguard Worker         }
298*795d594fSAndroid Build Coastguard Worker     };
299*795d594fSAndroid Build Coastguard Worker 
main(String[] args)300*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
301*795d594fSAndroid Build Coastguard Worker         Main theTest = new Main();
302*795d594fSAndroid Build Coastguard Worker         Thread gcThread = new Thread(causeGCs);
303*795d594fSAndroid Build Coastguard Worker         gcThread.setDaemon(true);  // Terminate if main thread dies.
304*795d594fSAndroid Build Coastguard Worker         gcThread.start();
305*795d594fSAndroid Build Coastguard Worker         theTest.testLoop();
306*795d594fSAndroid Build Coastguard Worker         pleaseStop = true;
307*795d594fSAndroid Build Coastguard Worker         gcThread.join();
308*795d594fSAndroid Build Coastguard Worker         System.out.println("Finished");
309*795d594fSAndroid Build Coastguard Worker     }
310*795d594fSAndroid Build Coastguard Worker }
311