# HG changeset patch # User jiangli # Date 1438372829 14400 # Node ID c2d4b23c9d1ce30eb16e89dd4883dcd2ba5394fe # Parent ed08afc96651b4ebb8ae2ce8e86e7467aadce4d6# Parent d7400a695eec6f5a2ed8749280244308bd515aaa Merge diff -r ed08afc96651 -r c2d4b23c9d1c jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java --- a/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Fri Jul 31 10:15:03 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Fri Jul 31 16:00:29 2015 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,6 +83,10 @@ add(); } + static ReferenceQueue getQueue() { + return queue; + } + /* Invoked by VM */ static void register(Object finalizee) { new Finalizer(finalizee); diff -r ed08afc96651 -r c2d4b23c9d1c jdk/src/java.base/share/classes/java/lang/ref/FinalizerHistogram.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/java/lang/ref/FinalizerHistogram.java Fri Jul 31 16:00:29 2015 -0400 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.lang.ref; + + +import java.util.Map; +import java.util.HashMap; +import java.util.Arrays; +import java.util.Comparator; + +/** + * This FinalizerHistogram class is for GC.finalizer_info diagnostic command support. + * It is invoked by the VM. + */ + +final class FinalizerHistogram { + + private static final class Entry { + private int instanceCount; + private final String className; + + int getInstanceCount() { + return instanceCount; + } + + void increment() { + instanceCount += 1; + } + + Entry(String className) { + this.className = className; + } + } + + // Method below is called by VM and VM expect certain + // entry class layout. + + static Entry[] getFinalizerHistogram() { + Map countMap = new HashMap<>(); + ReferenceQueue queue = Finalizer.getQueue(); + queue.forEach(r -> { + Object referent = r.get(); + if (referent != null) { + countMap.computeIfAbsent( + referent.getClass().getName(), Entry::new).increment(); + /* Clear stack slot containing this variable, to decrease + the chances of false retention with a conservative GC */ + referent = null; + } + }); + + Entry fhe[] = countMap.values().toArray(new Entry[countMap.size()]); + Arrays.sort(fhe, + Comparator.comparingInt(Entry::getInstanceCount).reversed()); + return fhe; + } +} diff -r ed08afc96651 -r c2d4b23c9d1c jdk/src/java.base/share/classes/java/lang/ref/Reference.java --- a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Fri Jul 31 10:15:03 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Fri Jul 31 16:00:29 2015 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,7 +101,7 @@ * Inactive: this */ @SuppressWarnings("rawtypes") - Reference next; + volatile Reference next; /* When active: next element in a discovered reference list maintained by GC (or this if last) * pending: next element in the pending list (or null if last) diff -r ed08afc96651 -r c2d4b23c9d1c jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java --- a/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Fri Jul 31 10:15:03 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Fri Jul 31 16:00:29 2015 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,8 @@ package java.lang.ref; +import java.util.function.Consumer; + /** * Reference queues, to which registered reference objects are appended by the * garbage collector after the appropriate reachability changes are detected. @@ -75,13 +77,12 @@ } } - @SuppressWarnings("unchecked") private Reference reallyPoll() { /* Must hold lock */ Reference r = head; if (r != null) { - head = (r.next == r) ? - null : - r.next; // Unchecked due to the next field having a raw type in Reference + @SuppressWarnings("unchecked") + Reference rn = r.next; + head = (rn == r) ? null : rn; r.queue = NULL; r.next = r; queueLength--; @@ -164,4 +165,32 @@ return remove(0); } + /** + * Iterate queue and invoke given action with each Reference. + * Suitable for diagnostic purposes. + * WARNING: any use of this method should make sure to not + * retain the referents of iterated references (in case of + * FinalReference(s)) so that their life is not prolonged more + * than necessary. + */ + void forEach(Consumer> action) { + for (Reference r = head; r != null;) { + action.accept(r); + @SuppressWarnings("unchecked") + Reference rn = r.next; + if (rn == r) { + if (r.queue == ENQUEUED) { + // still enqueued -> we reached end of chain + r = null; + } else { + // already dequeued: r.queue == NULL; -> + // restart from head when overtaken by queue poller(s) + r = head; + } + } else { + // next in chain + r = rn; + } + } + } } diff -r ed08afc96651 -r c2d4b23c9d1c jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java --- a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java Fri Jul 31 10:15:03 2015 -0700 +++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/Introspector.java Fri Jul 31 16:00:29 2015 -0400 @@ -552,8 +552,10 @@ // Java Beans introspection // Class clazz = complex.getClass(); - Method readMethod = JavaBeansAccessor.getReadMethod(clazz, element); - if (readMethod == null) { + Method readMethod; + if (JavaBeansAccessor.isAvailable()) { + readMethod = JavaBeansAccessor.getReadMethod(clazz, element); + } else { // Java Beans not available so use simple introspection // to locate method readMethod = SimpleIntrospector.getReadMethod(clazz, element); @@ -676,7 +678,12 @@ * {@code null} if no method is found. */ static Method getReadMethod(Class clazz, String property) { - // first character in uppercase (compatibility with JavaBeans) + if (Character.isUpperCase(property.charAt(0))) { + // the property name must start with a lower-case letter + return null; + } + // first character after 'get/is' prefix must be in uppercase + // (compatibility with JavaBeans) property = property.substring(0, 1).toUpperCase(Locale.ENGLISH) + property.substring(1); String getMethod = GET_METHOD_PREFIX + property; diff -r ed08afc96651 -r c2d4b23c9d1c jdk/test/com/sun/jmx/mbeanserver/introspector/BeanClass.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/BeanClass.java Fri Jul 31 16:00:29 2015 -0400 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +public class BeanClass { + public int getNumber() {return 1;} + public boolean isAvailable() {return false;} +} diff -r ed08afc96651 -r c2d4b23c9d1c jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/com/sun/jmx/mbeanserver/introspector/SimpleIntrospectorTest.java Fri Jul 31 16:00:29 2015 -0400 @@ -0,0 +1,104 @@ + +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.lang.reflect.Method; + +/* + * @test + * @bug 8129215 + * @summary The test checks whether the SimpleIntrospector is honoring the + * the JavaBeans property naming convention of always starting + * with a lower-case letter + * + * @author Jaroslav Bachorik + * @modules java.management + * @run clean SimpleIntrospectorTest + * @run build SimpleIntrospectorTest BeanClass + * @run main SimpleIntrospectorTest + */ +public class SimpleIntrospectorTest { + private static Method INTROSPECT_GETTER; + + public static void main(String ... args) throws Exception { + Class clz = Class.forName( + "com.sun.jmx.mbeanserver.Introspector$SimpleIntrospector" + ); + INTROSPECT_GETTER = clz.getDeclaredMethod( + "getReadMethod", + Class.class, + String.class + ); + INTROSPECT_GETTER.setAccessible(true); + boolean result = true; + result &= checkNumberValid(); + result &= checkNumberInvalid(); + result &= checkAvailableValid(); + result &= checkAvailableInvalid(); + + if (!result) { + throw new Error(); + } + } + + private static boolean checkNumberValid() throws Exception { + return checkGetter(false, "number"); + } + + private static boolean checkNumberInvalid() throws Exception { + return checkGetter(true, "Number"); + } + + private static boolean checkAvailableValid() throws Exception { + return checkGetter(false, "available"); + } + + private static boolean checkAvailableInvalid() throws Exception { + return checkGetter(true, "Available"); + } + + private static boolean checkGetter(boolean nullExpected, String name) + throws Exception { + Method m = getReadMethod(BeanClass.class, name); + boolean result = (m != null); + if (nullExpected) result = !result; + + if (result) { + return true; + } + if (nullExpected) { + System.err.println("SimpleIntrospector resolved an unknown getter " + + "for attribute '"+ name +"'"); + } else { + System.err.println("SimpleIntrospector fails to resolve getter " + + "for attribute '"+ name +"'"); + } + return false; + } + + private static Method getReadMethod(Class clz, String attr) + throws Exception { + return (Method)INTROSPECT_GETTER.invoke(null, clz, attr); + } +} diff -r ed08afc96651 -r c2d4b23c9d1c jdk/test/java/lang/ref/FinalizerHistogramTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/lang/ref/FinalizerHistogramTest.java Fri Jul 31 16:00:29 2015 -0400 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +import java.lang.reflect.Method; +import java.lang.reflect.Field; + +/* + * @test + * @summary Unit test for FinalizerHistogram + * @run main FinalizerHistogramTest + */ + +public class FinalizerHistogramTest { + static ReentrantLock lock = new ReentrantLock(); + static volatile int wasInitialized = 0; + static volatile int wasTrapped = 0; + static final int objectsCount = 1000; + + static class MyObject { + public MyObject() { + // Make sure object allocation/deallocation is not optimized out + wasInitialized += 1; + } + + protected void finalize() { + // Trap the object in a finalization queue + wasTrapped += 1; + lock.lock(); + } + } + + public static void main(String[] argvs) { + try { + lock.lock(); + for(int i = 0; i < objectsCount; ++i) { + new MyObject(); + } + System.out.println("Objects intialized: " + objectsCount); + System.gc(); + while(wasTrapped < 1); + + Class klass = Class.forName("java.lang.ref.FinalizerHistogram"); + + Method m = klass.getDeclaredMethod("getFinalizerHistogram"); + m.setAccessible(true); + Object entries[] = (Object[]) m.invoke(null); + + Class entryKlass = Class.forName("java.lang.ref.FinalizerHistogram$Entry"); + Field name = entryKlass.getDeclaredField("className"); + name.setAccessible(true); + Field count = entryKlass.getDeclaredField("instanceCount"); + count.setAccessible(true); + + System.out.println("Unreachable instances waiting for finalization"); + System.out.println("#instances class name"); + System.out.println("-----------------------"); + + boolean found = false; + for (Object entry : entries) { + Object e = entryKlass.cast(entry); + System.out.printf("%10d %s\n", count.get(e), name.get(e)); + if (((String) name.get(e)).indexOf("MyObject") != -1 ) { + found = true; + } + } + + if (!found) { + throw new RuntimeException("MyObject is not found in test output"); + } + + System.out.println("Test PASSED"); + } catch(Exception e) { + System.err.println("Test failed with " + e); + e.printStackTrace(System.err); + throw new RuntimeException("Test failed"); + } finally { + lock.unlock(); + } + } +}