1 /* 2 * Copyright (c) 2010, 2014, 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 import java.io.BufferedReader; 25 import java.io.InputStream; 26 import java.io.InputStreamReader; 27 28 import static jdk.testlibrary.Asserts.assertGreaterThan; 29 import jdk.testlibrary.ProcessTools; 30 31 import com.sun.tools.attach.AttachNotSupportedException; 32 import com.sun.tools.attach.VirtualMachine; 33 34 import sun.tools.attach.HotSpotVirtualMachine; 35 36 /* 37 * @test 38 * @bug 6942989 39 * @summary Check for WeakReference leak in Logger and anonymous Logger objects 40 * @library /lib/testlibrary 41 * @build jdk.testlibrary.* 42 * @run main/othervm TestLoggerWeakRefLeak Logger 43 * @run main/othervm TestLoggerWeakRefLeak AnonymousLogger 44 */ 45 public class TestLoggerWeakRefLeak { 46 47 private static final String TARGET_CLASS = "java.lang.ref.WeakReference"; 48 private static final int INSTANCE_COUNT = 100; 49 private static int loggerCount = 0; 50 51 public static void main(String[] args) throws Exception { 52 if (args[0].equals("Test for WeakReference leak in AnonymousLogger object")) { 53 System.out.println("AnonymousLogger"); 54 testIfLeaking(TestLoggerWeakRefLeak::callAnonymousLogger); 55 } else { 56 System.out.println("Test for WeakReference leak in Logger object"); 57 testIfLeaking(TestLoggerWeakRefLeak::callLogger); 58 } 59 } 60 61 /** 62 * For these particular WeakReference leaks, the count was always observed 63 * to be increasing so if decreasing or the same count is observed, 64 * then there is no leak. 65 */ 66 private static void testIfLeaking(Runnable callLogger) throws Exception { 67 long count = 0; 68 int instanceCount = 0; 69 int previousInstanceCount = 0; 70 int increasingCount = 0; 71 int decreasingCount = 0; 72 73 while (true) { 74 callLogger.run(); 75 count += INSTANCE_COUNT; 76 77 if ((count % 1000) == 0) { 78 System.out.println("call count = " + count); 79 80 instanceCount = getInstanceCountFromHeapHisto(); 81 if (instanceCount > previousInstanceCount) { 82 increasingCount++; 83 } else { 84 decreasingCount++; 85 System.out.println("increasing count: " + increasingCount); 86 System.out.println("decreasing or the same count: " + decreasingCount); 87 System.out.println("Test passed: decreasing or the same instance count is observed"); 88 break; 89 } 90 previousInstanceCount = instanceCount; 91 } 92 93 delayExecution(); 94 } 95 } 96 97 /** 98 * This Logger call is leaking two different WeakReferences: 99 * - one in LogManager.LogNode 100 * - one in Logger.kids 101 */ 102 private static void callLogger() { 103 for (int i = 0; i < INSTANCE_COUNT; i++) { 104 java.util.logging.Logger.getLogger("logger-" + loggerCount); 105 if (++loggerCount >= 25000) { 106 // Limit the Logger namespace used by the test so the weak refs 107 // in LogManager.loggers that are being properly managed 108 // don't skew the counts by too much. 109 loggerCount = 0; 110 } 111 } 112 } 113 114 /** 115 * This Logger call is leaking a WeakReference in Logger.kids 116 */ 117 private static void callAnonymousLogger() { 118 for (int i = 0; i < INSTANCE_COUNT; i++) { 119 java.util.logging.Logger.getAnonymousLogger(); 120 } 121 } 122 123 /** 124 * 'vm.heapHisto("-live")' will request a full GC 125 */ 126 private static int getInstanceCountFromHeapHisto() throws AttachNotSupportedException, Exception { 127 int instanceCount = 0; 128 129 HotSpotVirtualMachine vm = (HotSpotVirtualMachine) VirtualMachine 130 .attach(Integer.toString(ProcessTools.getProcessId())); 131 try { 132 try (InputStream heapHistoStream = vm.heapHisto("-live"); 133 BufferedReader in = new BufferedReader(new InputStreamReader(heapHistoStream))) { 134 String inputLine; 135 while ((inputLine = in.readLine()) != null) { 136 if (inputLine.contains(TARGET_CLASS)) { 137 instanceCount = Integer.parseInt(inputLine 138 .split("[ ]+")[2]); 139 System.out.println("instance count: " + instanceCount); 140 break; 141 } 142 } 143 } 144 } finally { 145 vm.detach(); 146 } 147 148 assertGreaterThan(instanceCount, 0, "No instances of " + TARGET_CLASS + " are found"); 149 150 return instanceCount; 151 } 152 153 /** 154 * Delay for 1/10 of a second to avoid CPU saturation 155 */ 156 private static void delayExecution() { 157 try { 158 Thread.sleep(100); 159 } catch (InterruptedException ie) { 160 // Ignore any exceptions 161 } 162 } 163 164 }