/* * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @key gc randomness * * @summary converted from VM Testbase gc/gctests/WeakReferenceGC. * VM Testbase keywords: [gc, nonconcurrent] * VM Testbase readme: * ******************************************* * set timeout = 25 when running this test * ******************************************* * This tests checks to see if the garbage collector enqueues * a weak reference when referrent has been turned to garbage. * Weak references are enqueued in a non-deterministic way * by the garbage collector, so the test uses a heuristic to * determine whether the references are being enqueued in a timely * manner which in turn determines whether outcome of the test. * IF the user invokes the test with the following command line * parameters : * java WeakReferenceGC -qFactor 0.9 -gcCount 5 * the test expects that 90% of all objects with only weak references * pointing to them will be enqueued within 5 calls to the garbage collector. * When I ran the test, I consistently got figures of 98% enqueueing * with just 1 call to the garbage collector. So if this test fails, * at its current settings, the garbage collector is not performing as well * as it used to. * The test creates circular linked lists of size 0.1Meg each. The number * of lists created can be set via the -numLists flag. The default * value is 50. * The circular linked lists have both strong and weak references pointing * to them. The strong and weak references are kept in arrays. * The strong references are all nulled out and System.gc() is called * explicitly and the heuristic is applied. If the test does not * satisfy the heuristic or an OutOfMemory exception is thrown, * the test fails. * Array containing Each circular linked list Array containing * weak references is 0.1 Meg each and has strong references * to linked lists. a weak reference, W and a to linked lists. * strong reference, x * pointing to it. * ---- ---------------------------- ----- * | | | ---- ---- <-| | | * | W1 |--> -->| |---.......>| | <---- | x1 | * | | -->| |<---.......| |<-- | | * ---- | ---- 1000 --- | ----- * --------------------------- * . . * . . * . . * . . * . . 10 * . . * ---- ---------------------------- ----- * | | | ---- ---- <-| | | * | Wn |--> -->| |---.......>| | <---- | xn | * | | -->| |<---.......| |<-- | | * ---- | ---- 1000 --- | ----- * --------------------------- * * @library /vmTestbase * /test/lib * @run driver jdk.test.lib.FileInstaller . . * @run main/othervm * gc.gctests.WeakReferenceGC.WeakReferenceGC * -numList 50 * -qFactor 0.9 * -gcCount 5 * -iter 100 */ package gc.gctests.WeakReferenceGC; import java.util.*; import java.lang.ref.*; import nsk.share.TestFailure; import nsk.share.gc.GC; import nsk.share.gc.ThreadedGCTest; import nsk.share.gc.gp.GarbageUtils; public class WeakReferenceGC extends ThreadedGCTest { // A heuristic is used to determine the outcome(pass/fail // status) of a test. If 90% of all objects that have // _only_ weak references pointing to them are garbage // collected with 5 explicit calls to the garbage collector // the test is deemed a pass. The following two variables // are used to define this heuristic: gcCount, qFactor static String args[]; CircularLinkedList holder[]; int loopCount = 100; // # of times test is performed int memory_reserve[]; int gcCount = 5; int numLists = 50; // number of linked lists float qFactor = (float) 0.9; ReferenceQueue refQueue; Vector results; WeakReference wholder[]; public static void main(String[] args) { WeakReferenceGC.args = args; GC.runTest(new WeakReferenceGC(), args); } WeakReferenceGC() { holder = new CircularLinkedList[numLists]; wholder = new WeakReference[numLists]; refQueue = new ReferenceQueue(); results = new Vector(); } protected Runnable createRunnable(int i) { return i > 0 ? null : new Worker(); } private void dumpTestResults() { double objectsRecovered; System.out.println("Percentage of Objects" + " # of GC's"); System.out.println(" Recovered " + " Required"); for (int i = 0; i < results.size(); i++) { Statistic s = (Statistic) results.elementAt(i); objectsRecovered = Math.rint((float) (s.numEnqueued) / (float) (numLists) * 100.0); System.out.println(" " + objectsRecovered + " % " + s.iterations); } } private boolean hasPassed() { boolean passed; passed = true; // assume passed till proven otherwise for (int i = 0; i < results.size(); i++) { Statistic s = (Statistic) results.elementAt(i); if ((s.iterations > gcCount) || (s.numEnqueued < (int) (numLists * qFactor))) { passed = false; break; // test failed } } return passed; } private void parseTestParams(String args[]) { for (int i = 0; i < args.length; i++) { if (args[i].compareTo("-numList") == 0) { numLists = new Integer(args[++i]).intValue(); } else if (args[i].compareTo("-qFactor") == 0) { qFactor = new Float(args[++i]).floatValue(); } else if (args[i].compareTo("-gcCount") == 0) { gcCount = new Integer(args[++i]).intValue(); } else if (args[i].compareTo("-iter") == 0) { loopCount = new Integer(args[++i]).intValue(); // } else { // System.err.println("usage : " + // "java WeakReferenceGC [-numList ] " + // "[-qFactor <0.x>] [-gcCount ] [-iter ]"); // throw new TestBug("Invalid arguments"); } } } private void persistentGC() { int numEnqueued, iter, qCriterion; numEnqueued = 0; // number of weakReference enqueued iter = 0; qCriterion = (int) (numLists * qFactor); while ((numEnqueued < qCriterion) && (iter <= gcCount)) { iter++; if (!getExecutionController().continueExecution()) { return; } if (GarbageUtils.eatMemory(getExecutionController()) == 0) { return; // We were unable to provoke OOME before timeout is over } numEnqueued = 0; // We set counter to zero to avoid counting references twice for (int i = 0; i < numLists; i++) { if (wholder[i].isEnqueued()) { numEnqueued++; } } } results.addElement((new Statistic(iter, numEnqueued))); } private void runTest() { int iter; iter = 1; try { do { for (int i = 0; i < numLists; i++) { holder[i] = new CircularLinkedList(); holder[i].addNelements(1000); wholder[i] = new WeakReference(holder[i], refQueue); } for (int i = 0; i < numLists; i++) { holder[i] = null; } if (!getExecutionController().continueExecution()) { return; } persistentGC(); iter++; } while (iter <= loopCount); } catch (OutOfMemoryError e) { memory_reserve = null; System.gc(); throw new TestFailure("Failed at iteration=" + loopCount); } } //We can't override run() method in WeakReferenceGC, so we are carrying out it to Worker private class Worker implements Runnable { @Override public void run() { parseTestParams(args); runTest(); dumpTestResults(); boolean passed = hasPassed(); if (passed == true) { log.info("Test passed."); } else { log.error("Test failed."); setFailed(true); } } } } class Statistic { int iterations; int numEnqueued; Statistic(int i, int num) { iterations = i; numEnqueued = num; } }