1 /* 2 * Copyright (c) 2020, 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 package gc; 25 26 /* @test 27 * @requires vm.gc != "Epsilon" 28 * @library /test/lib 29 * @build sun.hotspot.WhiteBox 30 * @modules java.base 31 * @run main ClassFileInstaller sun.hotspot.WhiteBox 32 * @run main/othervm 33 * -Xbootclasspath/a:. 34 * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 35 * gc.TestReferenceRefersTo 36 */ 37 38 import java.lang.ref.PhantomReference; 39 import java.lang.ref.Reference; 40 import java.lang.ref.ReferenceQueue; 41 import java.lang.ref.WeakReference; 42 import sun.hotspot.WhiteBox; 43 44 public class TestReferenceRefersTo { 45 private static final WhiteBox WB = WhiteBox.getWhiteBox(); 46 47 private static final class TestObject { 48 public final int value; 49 TestObject(int value)50 public TestObject(int value) { 51 this.value = value; 52 } 53 } 54 55 private static volatile TestObject testObjectNone = null; 56 private static volatile TestObject testObject1 = null; 57 private static volatile TestObject testObject2 = null; 58 private static volatile TestObject testObject3 = null; 59 private static volatile TestObject testObject4 = null; 60 61 private static ReferenceQueue<TestObject> queue = null; 62 63 private static PhantomReference<TestObject> testPhantom1 = null; 64 65 private static WeakReference<TestObject> testWeak2 = null; 66 private static WeakReference<TestObject> testWeak3 = null; 67 private static WeakReference<TestObject> testWeak4 = null; 68 setup()69 private static void setup() { 70 testObjectNone = new TestObject(0); 71 testObject1 = new TestObject(1); 72 testObject2 = new TestObject(2); 73 testObject3 = new TestObject(3); 74 testObject4 = new TestObject(4); 75 76 queue = new ReferenceQueue<TestObject>(); 77 78 testPhantom1 = new PhantomReference<TestObject>(testObject1, queue); 79 80 testWeak2 = new WeakReference<TestObject>(testObject2, queue); 81 testWeak3 = new WeakReference<TestObject>(testObject3, queue); 82 testWeak4 = new WeakReference<TestObject>(testObject4, queue); 83 } 84 gcUntilOld(Object o)85 private static void gcUntilOld(Object o) throws Exception { 86 if (!WB.isObjectInOldGen(o)) { 87 WB.fullGC(); 88 if (!WB.isObjectInOldGen(o)) { 89 fail("object not promoted by full gc"); 90 } 91 } 92 } 93 gcUntilOld()94 private static void gcUntilOld() throws Exception { 95 gcUntilOld(testObjectNone); 96 gcUntilOld(testObject1); 97 gcUntilOld(testObject2); 98 gcUntilOld(testObject3); 99 gcUntilOld(testObject4); 100 101 gcUntilOld(testPhantom1); 102 103 gcUntilOld(testWeak2); 104 gcUntilOld(testWeak3); 105 gcUntilOld(testWeak4); 106 } 107 progress(String msg)108 private static void progress(String msg) { 109 System.out.println(msg); 110 } 111 fail(String msg)112 private static void fail(String msg) throws Exception { 113 throw new RuntimeException(msg); 114 } 115 expectCleared(Reference<TestObject> ref, String which)116 private static void expectCleared(Reference<TestObject> ref, 117 String which) throws Exception { 118 expectNotValue(ref, testObjectNone, which); 119 if (!ref.refersTo(null)) { 120 fail("expected " + which + " to be cleared"); 121 } 122 } 123 expectNotCleared(Reference<TestObject> ref, String which)124 private static void expectNotCleared(Reference<TestObject> ref, 125 String which) throws Exception { 126 expectNotValue(ref, testObjectNone, which); 127 if (ref.refersTo(null)) { 128 fail("expected " + which + " to not be cleared"); 129 } 130 } 131 expectValue(Reference<TestObject> ref, TestObject value, String which)132 private static void expectValue(Reference<TestObject> ref, 133 TestObject value, 134 String which) throws Exception { 135 expectNotValue(ref, testObjectNone, which); 136 expectNotCleared(ref, which); 137 if (!ref.refersTo(value)) { 138 fail(which + " doesn't refer to expected value"); 139 } 140 } 141 expectNotValue(Reference<TestObject> ref, TestObject value, String which)142 private static void expectNotValue(Reference<TestObject> ref, 143 TestObject value, 144 String which) throws Exception { 145 if (ref.refersTo(value)) { 146 fail(which + " refers to unexpected value"); 147 } 148 } 149 checkInitialStates()150 private static void checkInitialStates() throws Exception { 151 expectValue(testPhantom1, testObject1, "testPhantom1"); 152 expectValue(testWeak2, testObject2, "testWeak2"); 153 expectValue(testWeak3, testObject3, "testWeak3"); 154 expectValue(testWeak4, testObject4, "testWeak4"); 155 } 156 discardStrongReferences()157 private static void discardStrongReferences() { 158 // testObjectNone not dropped 159 testObject1 = null; 160 testObject2 = null; 161 // testObject3 not dropped 162 testObject4 = null; 163 } 164 testConcurrentCollection()165 private static void testConcurrentCollection() throws Exception { 166 progress("setup concurrent collection test"); 167 setup(); 168 progress("gcUntilOld"); 169 gcUntilOld(); 170 171 progress("acquire control of concurrent cycles"); 172 WB.concurrentGCAcquireControl(); 173 try { 174 progress("check initial states"); 175 checkInitialStates(); 176 177 progress("discard strong references"); 178 discardStrongReferences(); 179 180 progress("run GC to before marking completed"); 181 WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED); 182 183 progress("fetch test objects, possibly keeping some alive"); 184 expectNotCleared(testPhantom1, "testPhantom1"); 185 expectNotCleared(testWeak2, "testWeak2"); 186 expectValue(testWeak3, testObject3, "testWeak3"); 187 188 // For some collectors, calling get() will keep testObject4 alive. 189 if (testWeak4.get() == null) { 190 fail("testWeak4 unexpectedly == null"); 191 } 192 193 progress("finish collection"); 194 WB.concurrentGCRunToIdle(); 195 196 progress("verify expected clears"); 197 expectCleared(testPhantom1, "testPhantom1"); 198 expectCleared(testWeak2, "testWeak2"); 199 expectValue(testWeak3, testObject3, "testWeak3"); 200 // This is true for all currently supported concurrent collectors. 201 expectNotCleared(testWeak4, "testWeak4"); 202 203 progress("verify get returns expected values"); 204 if (testWeak2.get() != null) { 205 fail("testWeak2.get() != null"); 206 } 207 208 TestObject obj3 = testWeak3.get(); 209 if (obj3 == null) { 210 fail("testWeak3.get() returned null"); 211 } else if (obj3.value != 3) { 212 fail("testWeak3.get().value is " + obj3.value); 213 } 214 215 TestObject obj4 = testWeak4.get(); 216 if (obj4 == null) { 217 fail("testWeak4.get() returned null"); 218 } else if (obj4.value != 4) { 219 fail("testWeak4.get().value is " + obj4.value); 220 } 221 222 progress("verify queue entries"); 223 long timeout = 60000; // 1 minute of milliseconds. 224 while (true) { 225 Reference<? extends TestObject> ref = queue.remove(timeout); 226 if (ref == null) { 227 break; 228 } else if (ref == testPhantom1) { 229 testPhantom1 = null; 230 } else if (ref == testWeak2) { 231 testWeak2 = null; 232 } else if (ref == testWeak3) { 233 testWeak3 = null; 234 } else if (ref == testWeak4) { 235 testWeak4 = null; 236 } else { 237 fail("unexpected reference in queue"); 238 } 239 } 240 if (testPhantom1 != null) { 241 fail("testPhantom1 not notified"); 242 } else if (testWeak2 != null) { 243 fail("testWeak2 not notified"); 244 } else if (testWeak3 == null) { 245 fail("testWeak3 notified"); 246 } else if (testWeak4 == null) { 247 if (obj4 != null) { 248 fail("testWeak4 notified"); 249 } 250 } 251 252 } finally { 253 progress("release control of concurrent cycles"); 254 WB.concurrentGCReleaseControl(); 255 } 256 progress("finished concurrent collection test"); 257 } 258 testSimpleCollection()259 private static void testSimpleCollection() throws Exception { 260 progress("setup simple collection test"); 261 setup(); 262 progress("gcUntilOld"); 263 gcUntilOld(); 264 265 progress("check initial states"); 266 checkInitialStates(); 267 268 progress("discard strong references"); 269 TestObject tw4 = testWeak4.get(); // Keep testObject4 alive. 270 discardStrongReferences(); 271 272 progress("collect garbage"); 273 WB.fullGC(); 274 275 progress("verify expected clears"); 276 expectCleared(testPhantom1, "testPhantom1"); 277 expectCleared(testWeak2, "testWeak2"); 278 expectValue(testWeak3, testObject3, "testWeak3"); 279 expectNotCleared(testWeak4, "testWeak4"); 280 281 progress("verify get returns expected values"); 282 if (testWeak2.get() != null) { 283 fail("testWeak2.get() != null"); 284 } else if (testWeak3.get() != testObject3) { 285 fail("testWeak3.get() is not expected value"); 286 } else if (testWeak4.get() != tw4) { 287 fail("testWeak4.get() is not expected value"); 288 } 289 290 progress("finished simple collection test"); 291 } 292 main(String[] args)293 public static void main(String[] args) throws Exception { 294 if (WB.supportsConcurrentGCBreakpoints()) { 295 testConcurrentCollection(); 296 } 297 testSimpleCollection(); 298 } 299 } 300