0N/A/*
3261N/A * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @test
0N/A * @bug 4530538
0N/A * @summary Basic unit test of
0N/A * RuntimeMXBean.getObjectPendingFinalizationCount()
0N/A * 1. GC and runFinalization() to get the current pending number
0N/A * 2. Create some number of objects with reference and without ref.
0N/A * 3. Clear all the references
0N/A * 4. GC and runFinalization() and the finalizable objects should
0N/A * be garbage collected.
0N/A * @author Alexei Guibadoulline and Mandy Chung
0N/A *
0N/A */
0N/A
0N/Aimport java.lang.management.*;
0N/A
0N/Apublic class Pending {
0N/A final static int NO_REF_COUNT = 600;
0N/A final static int REF_COUNT = 600;
0N/A final static int TOTAL_FINALIZABLE = (NO_REF_COUNT + REF_COUNT);
0N/A private static int finalized = 0;
0N/A private static MemoryMXBean mbean
0N/A = ManagementFactory.getMemoryMXBean();
0N/A
0N/A private static final String INDENT = " ";
0N/A private static void printFinalizerInstanceCount() {
0N/A if (!trace) return;
0N/A
0N/A int count = sun.misc.VM.getFinalRefCount();
0N/A System.out.println(INDENT + "Finalizable object Count = " + count);
0N/A
0N/A count = sun.misc.VM.getPeakFinalRefCount();
0N/A System.out.println(INDENT + "Peak Finalizable object Count = " + count);
0N/A }
0N/A
0N/A private static boolean trace = false;
0N/A public static void main(String argv[]) throws Exception {
0N/A if (argv.length > 0 && argv[0].equals("trace")) {
0N/A trace = true;
0N/A }
0N/A
2495N/A try {
2495N/A if (trace) {
2495N/A // Turn on verbose:gc to track GC
2495N/A mbean.setVerbose(true);
2495N/A }
2495N/A test();
2495N/A } finally {
2495N/A if (trace) {
2495N/A mbean.setVerbose(false);
2495N/A }
2495N/A }
2495N/A System.out.println("Test passed.");
2495N/A }
0N/A
2495N/A private static void test() throws Exception {
0N/A // Clean the memory and remove all objects that are pending
0N/A // finalization
0N/A System.gc();
0N/A Runtime.getRuntime().runFinalization();
0N/A
0N/A // Let the finalizer to finish
0N/A try {
0N/A Thread.sleep(200);
0N/A } catch (Exception e) {
0N/A throw e;
0N/A }
0N/A
0N/A // Create a number of new objects but no references to them
0N/A int startCount = mbean.getObjectPendingFinalizationCount();
0N/A
0N/A System.out.println("Number of objects pending for finalization:");
0N/A System.out.println(" Before creating object: " + startCount +
0N/A " finalized = " + finalized);
0N/A printFinalizerInstanceCount();
0N/A
0N/A for (int i = 0; i < NO_REF_COUNT; i++) {
0N/A new MyObject();
0N/A }
0N/A
0N/A Snapshot snapshot = getSnapshot();
0N/A System.out.println(" Afer creating objects with no ref: " + snapshot);
0N/A printFinalizerInstanceCount();
0N/A
0N/A Object[] objs = new Object[REF_COUNT];
0N/A for (int i = 0; i < REF_COUNT; i++) {
0N/A objs[i] = new MyObject();
0N/A }
0N/A snapshot = getSnapshot();
0N/A System.out.println(" Afer creating objects with ref: " + snapshot);
0N/A printFinalizerInstanceCount();
0N/A
0N/A // Now check the expected count - GC and runFinalization will be
0N/A // invoked.
0N/A checkFinalizerCount(NO_REF_COUNT, 0);
0N/A
0N/A // Clean the memory and remove all objects that are pending
0N/A // finalization again
0N/A objs = null;
0N/A snapshot = getSnapshot();
0N/A System.out.println("Clear all references finalized = " + snapshot);
0N/A printFinalizerInstanceCount();
0N/A
0N/A checkFinalizerCount(TOTAL_FINALIZABLE, NO_REF_COUNT);
0N/A
0N/A snapshot = getSnapshot();
0N/A printFinalizerInstanceCount();
0N/A
0N/A // Check the mbean now
0N/A if (snapshot.curFinalized != TOTAL_FINALIZABLE) {
0N/A throw new RuntimeException("Wrong number of finalized objects "
0N/A + snapshot + ". Expected "
0N/A + TOTAL_FINALIZABLE);
0N/A }
0N/A
0N/A if (startCount != 0 || snapshot.curPending != 0) {
0N/A throw new RuntimeException("Wrong number of objects pending "
0N/A + "finalization start = " + startCount
0N/A + " end = " + snapshot);
0N/A }
0N/A
0N/A }
0N/A
0N/A private static void checkFinalizerCount(int expectedTotal, int curFinalized)
0N/A throws Exception {
0N/A int prevCount = -1;
0N/A Snapshot snapshot = getSnapshot();
0N/A if (snapshot.curFinalized != curFinalized) {
0N/A throw new RuntimeException(
0N/A "Unexpected finalized objects: " + snapshot +
0N/A " but expected = " + curFinalized);
0N/A }
0N/A int MAX_GC_LOOP = 6;
0N/A for (int i = 1;
0N/A snapshot.curFinalized != expectedTotal && i <= MAX_GC_LOOP;
0N/A i++) {
0N/A System.gc();
0N/A
0N/A // Pause to give a chance to Finalizer thread to run
0N/A pause();
0N/A
0N/A printFinalizerInstanceCount();
0N/A // Race condition may occur; attempt to check this
0N/A // a few times before throwing exception.
0N/A for (int j = 0; j < 5; j++) {
0N/A // poll for another current pending count
0N/A snapshot = getSnapshot();
0N/A if (snapshot.curFinalized == expectedTotal ||
0N/A snapshot.curPending != 0) {
0N/A break;
0N/A }
0N/A }
0N/A System.out.println(" After GC " + i + ": " + snapshot);
0N/A
0N/A Runtime.getRuntime().runFinalization();
0N/A
0N/A // Pause to give a chance to Finalizer thread to run
0N/A pause();
0N/A
0N/A snapshot = getSnapshot();
0N/A if (snapshot.curFinalized == expectedTotal &&
0N/A snapshot.curPending != 0) {
0N/A throw new RuntimeException(
0N/A "Unexpected current number of objects pending for " +
0N/A "finalization: " + snapshot + " but expected = 0");
0N/A }
0N/A
0N/A System.out.println(" After runFinalization " + i + ": " + snapshot);
0N/A printFinalizerInstanceCount();
0N/A
0N/A try {
0N/A Thread.sleep(1000);
0N/A } catch (Exception e) {
0N/A throw e;
0N/A }
0N/A }
0N/A if (snapshot.curFinalized != expectedTotal) {
0N/A throw new RuntimeException(
0N/A "Unexpected current number of objects pending for " +
0N/A "finalization: " + snapshot + " but expected > 0");
0N/A }
0N/A }
0N/A
0N/A private static Object lock = new Object();
0N/A private static class MyObject {
0N/A Object[] dummy = new Object[10];
0N/A public void finalize () {
0N/A synchronized (lock) {
0N/A finalized++;
0N/A }
0N/A }
0N/A }
0N/A
0N/A static class Snapshot {
0N/A public int curFinalized;
0N/A public int curPending;
0N/A Snapshot(int f, int p) {
0N/A curFinalized = f;
0N/A curPending = p;
0N/A }
0N/A public String toString() {
0N/A return "Current finalized = " + curFinalized +
0N/A " Current pending = " + curPending;
0N/A }
0N/A }
0N/A
0N/A private static Snapshot getSnapshot() {
0N/A synchronized (lock) {
0N/A int curCount = mbean.getObjectPendingFinalizationCount();
0N/A return new Snapshot(finalized, curCount);
0N/A }
0N/A }
0N/A
0N/A private static Object pauseObj = new Object();
0N/A private static void pause() {
0N/A // Enter lock a without blocking
0N/A synchronized (pauseObj) {
0N/A try {
0N/A // may need to tune this timeout for different platforms
0N/A pauseObj.wait(20);
0N/A } catch (Exception e) {
0N/A System.err.println("Unexpected exception.");
0N/A e.printStackTrace(System.err);
0N/A }
0N/A }
0N/A }
0N/A}