1 /* 2 * Copyright (c) 1997, 2016, 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 /* @test 25 * @run main/othervm -Xmx16m EphemeronTests 26 * @summary Basic functional tests for Ephemerons 27 * @author Peter Levart 28 */ 29 30 import java.lang.ref.Ephemeron; 31 import java.lang.ref.Reference; 32 import java.lang.ref.SoftReference; 33 import java.lang.ref.WeakReference; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.function.Function; 37 38 public class EphemeronTests { 39 40 public static void main(String[] args) throws Exception { 41 42 testValueToKeyChain(100, true); 43 testValueToKeyChain(100, false); 44 45 testReachability(SoftReference::new); 46 testReachability(WeakReference::new); 47 } 48 49 static class Key { 50 final int i; 51 52 Key(int i) { 53 this.i = i; 54 } 55 56 @Override 57 public String toString() { 58 return "k" + i; 59 } 60 } 61 62 static class Value { 63 final Key key; 64 65 Value(Key key) { 66 this.key = key; 67 } 68 69 @Override 70 public String toString() { 71 return "v(" + key + ")"; 72 } 73 } 74 75 static class Eph extends Ephemeron<Key, Value> { 76 public Eph(Key key, Value value) { 77 super(key, value); 78 } 79 80 @Override 81 public String toString() { 82 return getKey() + "=" + getValue(); 83 } 84 } 85 86 static void testValueToKeyChain(int size, boolean forwardChaining) throws Exception { 87 System.out.println(); 88 System.out.println((forwardChaining ? "Forward" : "Backward") + 89 " chaining of value->key ..."); 90 System.out.println(); 91 List<Eph> ephs = new ArrayList<>(size); 92 93 Key k1 = new Key(1); 94 { 95 Key kp = k1; 96 for (int i = 2; i <= size; i++) { 97 Key ki = new Key(i); 98 ephs.add( 99 forwardChaining 100 ? new Eph(kp, new Value(ki)) 101 : new Eph(ki, new Value(kp)) 102 ); 103 kp = ki; 104 } 105 ephs.add( 106 forwardChaining 107 ? new Eph(kp, new Value(k1)) 108 : new Eph(k1, new Value(kp)) 109 ); 110 kp = null; 111 } 112 113 fillHeap(); 114 System.out.println("1: " + toString(ephs)); 115 for (Eph eph : ephs) assertAlive(eph); 116 k1.getClass(); // reachabilityFence 117 118 k1 = null; 119 fillHeap(); 120 System.out.println("2: " + toString(ephs)); 121 for (Eph eph : ephs) assertCleared(eph); 122 } 123 124 static void testReachability(Function<Object, Reference<Object>> referenceConstructor) { 125 Reference<Object> kRef, vRef; 126 Ephemeron<Object, Object> eph; 127 Object k; 128 { 129 k = new Object(); 130 Object v = new Object(); 131 kRef = referenceConstructor.apply(k); 132 vRef = referenceConstructor.apply(v); 133 eph = new Ephemeron<>(k, v); 134 v = null; 135 } 136 137 System.out.println(); 138 System.out.println(kRef.getClass().getSimpleName() + " reachability test"); 139 System.out.println(); 140 141 while (true) { 142 fillHeap(); 143 if ((k = kRef.get()) == null) { 144 System.out.println("key cleared"); 145 assertCleared(kRef); 146 assertCleared(eph); 147 assertCleared(vRef); 148 break; 149 } else { 150 System.out.println("key alive"); 151 assertAlive(kRef); 152 assertAlive(eph); 153 assertAlive(vRef); 154 k.getClass(); // reachabilityFence 155 } 156 k = null; 157 } 158 } 159 160 // utils 161 162 static void fillHeap() { 163 long t0 = System.nanoTime(); 164 Object junk = null; 165 try { 166 while (true) { 167 Object[] nj = new Object[16384]; 168 nj[0] = junk; 169 junk = nj; 170 nj = null; 171 } 172 } catch (OutOfMemoryError e) { 173 junk = null; 174 System.gc(); 175 } 176 long t = System.nanoTime() - t0; 177 System.out.println("Fill Heap (" + (t / 1000000L) + " ms)"); 178 try { 179 Thread.sleep(100L); 180 } catch (InterruptedException e) {} 181 } 182 183 static void assertAlive(Reference<?> reference) { 184 if (reference.get() == null) { 185 throw new AssertionError(reference + " is cleared"); 186 } 187 } 188 189 static void assertAlive(Ephemeron<?, ?> ephemeron) { 190 if (ephemeron.getKey() == null || ephemeron.getValue() == null) { 191 throw new AssertionError(ephemeron + " is cleared"); 192 } 193 } 194 195 static void assertCleared(Reference<?> reference) { 196 if (reference.get() != null) { 197 throw new AssertionError(reference + " is not cleared"); 198 } 199 } 200 201 static void assertCleared(Ephemeron<?, ?> ephemeron) { 202 if (ephemeron.getKey() != null || ephemeron.getValue() != null) { 203 throw new AssertionError(ephemeron + " is not cleared"); 204 } 205 } 206 207 static String toString(List<?> list) { 208 if (list == null) return "null"; 209 if (list.size() <= 10) return list.toString(); 210 String prefix = list.subList(0, 5).toString(); 211 String suffix = list.subList(list.size() - 5, list.size()).toString(); 212 213 return prefix.substring(0, prefix.length() - 1) + ", ..., " + suffix.substring(1); 214 } 215 }