1 /* 2 * Copyright (c) 2002, 2021, 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 * @key stress randomness 27 * 28 * @summary converted from VM Testbase gc/gctests/ReferencesGC. 29 * VM Testbase keywords: [gc, stress, stressopt, nonconcurrent, quick] 30 * 31 * @library /vmTestbase 32 * /test/lib 33 * @run main/othervm 34 * -XX:-UseGCOverheadLimit 35 * gc.gctests.ReferencesGC.ReferencesGC 36 * -range 200 37 * -ratio 0.9 38 * -t 1 39 */ 40 41 package gc.gctests.ReferencesGC; 42 43 import java.lang.ref.*; 44 import nsk.share.TestFailure; 45 import nsk.share.gc.Algorithms; 46 import nsk.share.gc.GC; 47 import nsk.share.gc.ThreadedGCTest; 48 import nsk.share.gc.gp.GarbageProducer; 49 import nsk.share.gc.gp.GarbageUtils; 50 import nsk.share.test.ExecutionController; 51 52 public class ReferencesGC extends ThreadedGCTest { 53 54 static int RANGE = 256; 55 static float RATIO = (float) 1.0; 56 static int REMOVE; // Initialized in parseArgs. 57 static int RETAIN; // Initialized in parseArgs. 58 main(String[] args)59 public static void main(String[] args) { 60 parseArgs(args); 61 GC.runTest(new ReferencesGC(), args); 62 } 63 parseArgs(String[] args)64 public static void parseArgs(String[] args) { 65 for (int i = 0; i < args.length; i++) { 66 if (args[i].compareTo("-range") == 0) { 67 RANGE = Integer.valueOf(args[++i]).intValue(); 68 } else if (args[i].compareTo("-ratio") == 0) { 69 RATIO = Float.valueOf(args[++i]).floatValue(); 70 } 71 } 72 REMOVE = (int) (RANGE * RATIO); 73 RETAIN = RANGE - REMOVE; 74 } 75 76 private class Worker implements Runnable { 77 78 static final int WEAK = 0; 79 static final int SOFT = 1; 80 static final int PHANTOM = 2; 81 private ExecutionController stresser; 82 int finalizationMaxTime = 1000 * 60 * runParams.getNumberOfThreads(); 83 ReferenceQueue refq = null; // Reinitialized each time through loop 84 int[] alive = null; // Reinitialized each time through loop 85 int[] wrong = null; // Reinitialized each time through loop 86 CircularLinkedList holder[] = new CircularLinkedList[RANGE]; 87 WeakReference wr[] = new WeakReference[RANGE]; 88 SoftReference sr[] = new SoftReference[RANGE]; 89 PhantomReference phr[] = new PhantomReference[RANGE]; 90 GarbageProducer gp = GarbageUtils.getArrayProducers().get(0); 91 int iter = 0; 92 93 @Override run()94 public void run() { 95 if (stresser == null) { 96 stresser = getExecutionController(); 97 } 98 99 while (stresser.continueExecution()) { 100 int totalLive = 0; 101 try { 102 refq = new ReferenceQueue(); 103 alive = new int[3]; 104 wrong = new int[3]; 105 for (int j = 0; j < RANGE; j++) { 106 holder[j] = new CircularLinkedList(); 107 holder[j].addNelements(300); 108 wr[j] = new WeakReference(holder[j], refq); 109 sr[j] = new SoftReference(holder[j], refq); 110 phr[j] = new PhantomReference(holder[j], refq); 111 } 112 } catch (OutOfMemoryError oome) { 113 // we should just skip the test 114 // the other thread could eat all memory 115 continue; 116 } 117 118 for (int i = 0; i < RANGE; i++) { 119 if (wr[i].refersTo(holder[i])) { 120 ++totalLive; 121 } 122 if (sr[i].refersTo(holder[i])) { 123 ++totalLive; 124 } 125 if (phr[i].refersTo(holder[i])) { 126 ++totalLive; 127 } 128 } 129 if (totalLive != 3 * RANGE) { 130 throw new TestFailure("There are " + (3 * RANGE - totalLive) + " references cleared before null-assigment."); 131 } 132 133 for (int i = 0; i < REMOVE; i++) { 134 holder[i] = null; 135 } 136 137 Algorithms.eatMemory(stresser); 138 if (!stresser.continueExecution()) { 139 break; 140 } 141 // At this point OOME was thrown and accordingly to spec 142 // all weak refs should be processed 143 144 long waitTime = System.currentTimeMillis() + finalizationMaxTime; 145 int totalQ = 0; 146 while ((totalQ < (3 * REMOVE)) && (System.currentTimeMillis() < waitTime)) { 147 alive[WEAK] = alive[SOFT] = alive[PHANTOM] = 0; 148 wrong[WEAK] = wrong[SOFT] = wrong[PHANTOM] = 0; 149 for (int i = 0; i < RANGE; i++) { 150 if (!wr[i].refersTo(holder[i])) { 151 ++wrong[WEAK]; 152 } else if (holder[i] != null) { 153 ++alive[WEAK]; 154 } 155 156 if (!sr[i].refersTo(holder[i])) { 157 ++wrong[SOFT]; 158 } else if (holder[i] != null) { 159 ++alive[SOFT]; 160 } 161 162 if (!phr[i].refersTo(holder[i])) { 163 ++wrong[PHANTOM]; 164 } else if (holder[i] != null) { 165 ++alive[PHANTOM]; 166 } 167 } 168 169 try { 170 while (refq.remove(100) != null) { 171 ++totalQ; 172 } 173 } catch (InterruptedException ie) { 174 } 175 if (totalQ < (3 * REMOVE)) { 176 log.debug("After null-assignment to " + REMOVE + 177 " referent values and provoking gc found:\n\t" + 178 totalQ + " queued refs."); 179 try { 180 log.debug("sleeping to give reference processing more time ..."); 181 Thread.sleep(1000); 182 } catch (InterruptedException ie) { 183 } 184 } 185 } 186 log.debug("iteration.... " + iter++); 187 if (wrong[WEAK] != 0) { 188 throw new TestFailure("Expected " + RETAIN + " weak references still alive: " + alive[WEAK]); 189 } else if (wrong[SOFT] != 0) { 190 throw new TestFailure("Expected " + RETAIN + " soft references still alive: " + alive[SOFT]); 191 } else if (wrong[PHANTOM] != 0) { 192 throw new TestFailure("Expected " + RETAIN + " phantom references still alive: " + alive[PHANTOM]); 193 } else if (totalQ != (3 * REMOVE)) { 194 throw new TestFailure("Expected " + (3 * REMOVE) + " references enqueued: " + totalQ); 195 } 196 } 197 } 198 } 199 200 @Override createRunnable(int i)201 protected Runnable createRunnable(int i) { 202 return new Worker(); 203 } 204 } 205