1 /* 2 * Copyright (c) 2007, 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 * @bug 4405807 26 * @run main/othervm -Xms10m ReferencesTest 27 * @summary Verify that references from ResourceBundle cache don't prevent 28 * class loader reclamation. 29 */ 30 31 import java.io.File; 32 import java.lang.ref.WeakReference; 33 import java.lang.reflect.Field; 34 import java.net.URL; 35 import java.net.URLClassLoader; 36 import java.util.Locale; 37 import java.util.Map; 38 import java.util.MissingResourceException; 39 import java.util.ResourceBundle; 40 41 /** 42 * This test relies on the current behavior of the garbage collector and is 43 * therefore no clear indicator of whether the fix for 4405807 works. 44 * If the test fails, it might indicate a regression, or it might just mean 45 * that a less aggressive garbage collector is used. 46 */ 47 public class ReferencesTest { 48 49 private static final int CLASS_LOADER_COUNT = 20; 50 51 // These two parallel arrays have references to the same class loaders. 52 // The weakLoaders array lets us track whether class loaders are being 53 // reclaimed after the references in the loaders array are nulled out. 54 private static ClassLoader[] loaders = new ClassLoader[CLASS_LOADER_COUNT]; 55 private static WeakReference[] weakLoaders = new WeakReference[CLASS_LOADER_COUNT]; 56 57 public static void main(String[] args) throws Exception { 58 59 URL testDirectory = new File(System.getProperty("test.classes", ".")).toURL(); 60 61 for (int i = 0; i < loaders.length; i++) { 62 URL[] urls = { testDirectory }; 63 loaders[i] = new URLClassLoader(urls); 64 weakLoaders[i] = new WeakReference(loaders[i]); 65 } 66 67 // fill the ResourceBundle cache with entries for half the class loaders 68 loadBundles(0, CLASS_LOADER_COUNT / 2); 69 70 report("After loading resource bundles for first half of class loaders: "); 71 72 // release the first half of the class loaders 73 for (int i = 0; i < CLASS_LOADER_COUNT / 2; i++) { 74 loaders[i] = null; 75 } 76 77 System.gc(); 78 79 report("After releasing first half of class loaders: "); 80 81 // fill the ResourceBundle cache with entries for second half the class loaders 82 loadBundles(CLASS_LOADER_COUNT / 2, CLASS_LOADER_COUNT); 83 84 report("After loading resource bundles for second half of class loaders: "); 85 86 // release the second half of the class loaders 87 for (int i = CLASS_LOADER_COUNT / 2; i < CLASS_LOADER_COUNT; i++) { 88 loaders[i] = null; 89 } 90 91 System.gc(); 92 93 report("After releasing second half of class loaders: "); 94 95 // The garbage collector in Tiger actually has reclaimed all class 96 // loaders at this point, but in order not to become too dependent 97 // on the current behavior, we only require that the first half 98 // has been reclaimed. 99 if (countLoaders(0, CLASS_LOADER_COUNT / 2) > 0) { 100 throw new RuntimeException("Too many class loaders not reclaimed yet."); 101 } 102 } 103 104 private static void report(String when) throws Exception { 105 int first = countLoaders(0, CLASS_LOADER_COUNT / 2); 106 int second = countLoaders(CLASS_LOADER_COUNT / 2, CLASS_LOADER_COUNT); 107 108 System.out.println(when); 109 System.out.println(" " + first + " loaders alive in first half"); 110 System.out.println(" " + second + " loaders alive in second half"); 111 } 112 113 private static void loadBundles(int start, int end) throws Exception { 114 for (int i = start; i < end; i++) { 115 // There's no resource bundle for NonExistantBundle - this 116 // let's us test the case where a resource bundle is not found, 117 // which in the past created a SoftReference on the value side 118 // of the cache. 119 try { 120 ResourceBundle.getBundle("NonExistantBundle", Locale.US, loaders[i]); 121 } catch (MissingResourceException e) { 122 } 123 // There's a base resource bundle for ReferencesTestBundle - the 124 // normal case. 125 ResourceBundle.getBundle("ReferencesTestBundle", Locale.US, loaders[i]); 126 } 127 } 128 129 private static int countLoaders(int start, int end) { 130 int count = 0; 131 for (int i = start; i < end; i++) { 132 if (weakLoaders[i].get() != null) { 133 count++; 134 } 135 } 136 return count; 137 } 138 }