1 /*
   2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /*
  25  * @test
  26  * @bug     4530538
  27  * @modules java.base/jdk.internal.misc
  28  *          java.management
  29  * @summary Basic unit test of
  30  *          RuntimeMXBean.getObjectPendingFinalizationCount()
  31  *          1. GC and runFinalization() to get the current pending number
  32  *          2. Create some number of objects with reference and without ref.
  33  *          3. Clear all the references
  34  *          4. GC and runFinalization() and the finalizable objects should
  35  *             be garbage collected.
  36  * @author  Alexei Guibadoulline and Mandy Chung
  37  */
  38 
  39 import java.lang.management.*;
  40 
  41 public class Pending {
  42     static final int NO_REF_COUNT = 600;
  43     static final int REF_COUNT = 500;
  44     static final int TOTAL_FINALIZABLE = (NO_REF_COUNT + REF_COUNT);
  45     private static int finalized = 0;
  46     private static MemoryMXBean mbean
  47         = ManagementFactory.getMemoryMXBean();
  48 
  49     private static final String INDENT = "      ";
  50     private static void printFinalizerInstanceCount() {
  51         if (!trace) return;
  52 
  53         int count = jdk.internal.misc.VM.getFinalRefCount();
  54         System.out.println(INDENT + "Finalizable object Count = " + count);
  55 
  56         count = jdk.internal.misc.VM.getPeakFinalRefCount();
  57         System.out.println(INDENT + "Peak Finalizable object Count = " + count);
  58     }
  59 
  60     private static boolean trace = false;
  61     public static void main(String argv[]) throws Exception {
  62         if (argv.length > 0 && argv[0].equals("trace")) {
  63             trace = true;
  64         }
  65 
  66         try {
  67             if (trace) {
  68                 // Turn on verbose:gc to track GC
  69                 mbean.setVerbose(true);
  70             }
  71             test();
  72         } finally {
  73             if (trace) {
  74                 mbean.setVerbose(false);
  75             }
  76         }
  77         System.out.println("Test passed.");
  78     }
  79 
  80     // Keep objs public so the optimizer will not remove them too early.
  81     public static Object[] objs = null;
  82 
  83     private static void test() throws Exception {
  84         // Clean the memory and remove all objects that are pending
  85         // finalization
  86         System.gc();
  87         Snapshot snapshot = getSnapshotAfterFinalization();
  88 
  89         System.out.println("Number of objects pending for finalization:");
  90         System.out.println("   Before creating object: " + snapshot);
  91         printFinalizerInstanceCount();
  92 
  93         // Create objects without saving reference. Should be removed at next GC.
  94         for (int i = 0; i < NO_REF_COUNT; i++) {
  95             new MyObject();
  96         }
  97 
  98         snapshot = getSnapshot();
  99         System.out.println("   Afer creating objects with no ref: " + snapshot);
 100         printFinalizerInstanceCount();
 101 
 102         // Create objects and save references.
 103         objs = new Object[REF_COUNT];
 104         for (int i = 0; i < REF_COUNT; i++) {
 105             objs[i] = new MyObject();
 106         }
 107         snapshot = getSnapshot();
 108         System.out.println("   Afer creating objects with ref: " + snapshot);
 109         printFinalizerInstanceCount();
 110 
 111         // Now check the expected count - GC and runFinalization will be
 112         // invoked.
 113         checkFinalizerCount(NO_REF_COUNT, 0);
 114 
 115         // Clean the memory and remove all objects that are pending
 116         // finalization again
 117         objs = null;
 118         snapshot = getSnapshot();
 119         System.out.println("Clear all references finalized = " + snapshot);
 120         printFinalizerInstanceCount();
 121 
 122         checkFinalizerCount(TOTAL_FINALIZABLE, NO_REF_COUNT);
 123 
 124         snapshot = getSnapshot();
 125         printFinalizerInstanceCount();
 126 
 127         // Check the mbean now
 128         if (snapshot.curFinalized != TOTAL_FINALIZABLE) {
 129             throw new RuntimeException("Wrong number of finalized objects "
 130                                      + snapshot + ". Expected "
 131                                      + TOTAL_FINALIZABLE);
 132         }
 133 
 134         if (snapshot.curPending != 0) {
 135             throw new RuntimeException("Wrong number of objects pending "
 136                                      + " end = " + snapshot);
 137         }
 138 
 139     }
 140 
 141     private static void checkFinalizerCount(int expectedTotal, int curFinalized)
 142         throws Exception {
 143         int prevCount = -1;
 144         Snapshot snapshot = getSnapshot();
 145         if (snapshot.curFinalized != curFinalized) {
 146             throw new RuntimeException(
 147                     "Unexpected finalized objects: " + snapshot +
 148                     " but expected = " + curFinalized);
 149         }
 150         int MAX_GC_LOOP = 6;
 151         for (int i = 1;
 152              snapshot.curFinalized != expectedTotal && i <= MAX_GC_LOOP;
 153              i++) {
 154             System.gc();
 155             snapshot = getSnapshotAfterFinalization();
 156 
 157             if (snapshot.curFinalized == expectedTotal &&
 158                 snapshot.curPending != 0) {
 159                 throw new RuntimeException(
 160                     "Unexpected current number of objects pending for " +
 161                     "finalization: " + snapshot + " but expected = 0");
 162             }
 163 
 164             System.out.println("   After runFinalization " + i + ": " + snapshot);
 165             printFinalizerInstanceCount();
 166 
 167             try {
 168                 Thread.sleep(1000);
 169             } catch (Exception e) {
 170                 throw e;
 171             }
 172         }
 173         if (snapshot.curFinalized != expectedTotal) {
 174             throw new RuntimeException(
 175                 "Unexpected current number of objects pending for " +
 176                 "finalization: " + snapshot + " but expected > 0");
 177         }
 178     }
 179 
 180     private static Object lock = new Object();
 181     private static class MyObject {
 182         Object[] dummy = new Object[10];
 183         public void finalize () {
 184             synchronized (lock) {
 185                 finalized++;
 186             }
 187         }
 188     }
 189 
 190     static class Snapshot {
 191         public int curFinalized;
 192         public int curPending;
 193         Snapshot(int f, int p) {
 194             curFinalized = f;
 195             curPending = p;
 196         }
 197         public String toString() {
 198             return "Current finalized = " + curFinalized +
 199                    " Current pending = " + curPending;
 200         }
 201     }
 202 
 203     private static Snapshot getSnapshot() {
 204         synchronized (lock) {
 205             int curCount = mbean.getObjectPendingFinalizationCount();
 206             return new Snapshot(finalized, curCount);
 207         }
 208     }
 209 
 210     // Repeat getSnapshot until no pending finalization.
 211     private static Snapshot getSnapshotAfterFinalization() throws Exception {
 212         int loopCount = 0;
 213         Snapshot snapshot = null;
 214         while (loopCount < 100) {
 215             Runtime.getRuntime().runFinalization();
 216             Thread.sleep(50);
 217             snapshot = getSnapshot();
 218             if (snapshot.curPending == 0) {
 219                 return snapshot;
 220             }
 221             ++loopCount;
 222             System.out.println("Waiting for curPending to be 0. snapshot=" + snapshot);
 223         }
 224         String msg = "Objects pending finalization is not 0. snapshot=%s";
 225         throw new RuntimeException(String.format(msg, snapshot));
 226     }
 227 }