changeset 8676:5801df4acb84

8059036: Implement Diagnostic Commands for heap and finalizerinfo Summary: Implement Diagnostic Commands for heap and finalizerinfo Reviewed-by: mchung
author dbuck
date Mon, 18 Dec 2017 18:53:34 -0500
parents 8c3e62bb99f3
children 438da598a947
files src/share/vm/classfile/vmSymbols.hpp src/share/vm/services/diagnosticCommand.cpp src/share/vm/services/diagnosticCommand.hpp test/serviceability/dcmd/gc/FinalizerInfoTest.java test/serviceability/dcmd/gc/HeapInfoTest.java
diffstat 5 files changed, 236 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/classfile/vmSymbols.hpp	Mon Dec 11 02:39:24 2017 -0800
+++ b/src/share/vm/classfile/vmSymbols.hpp	Mon Dec 18 18:53:34 2017 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -569,6 +569,11 @@
   template(java_lang_management_ThreadInfo_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;)V") \
   template(java_lang_management_ThreadInfo_with_locks_constructor_signature, "(Ljava/lang/Thread;ILjava/lang/Object;Ljava/lang/Thread;JJJJ[Ljava/lang/StackTraceElement;[Ljava/lang/Object;[I[Ljava/lang/Object;)V") \
   template(long_long_long_long_void_signature,         "(JJJJ)V")                                                 \
+  template(finalizer_histogram_klass,                  "java/lang/ref/FinalizerHistogram")                        \
+  template(void_finalizer_histogram_entry_array_signature,  "()[Ljava/lang/ref/FinalizerHistogram$Entry;")                        \
+  template(get_finalizer_histogram_name,               "getFinalizerHistogram")                                   \
+  template(finalizer_histogram_entry_name_field,       "className")                                               \
+  template(finalizer_histogram_entry_count_field,      "instanceCount")                                           \
                                                                                                                   \
   template(java_lang_management_MemoryPoolMXBean,      "java/lang/management/MemoryPoolMXBean")                   \
   template(java_lang_management_MemoryManagerMXBean,   "java/lang/management/MemoryManagerMXBean")                \
--- a/src/share/vm/services/diagnosticCommand.cpp	Mon Dec 11 02:39:24 2017 -0800
+++ b/src/share/vm/services/diagnosticCommand.cpp	Mon Dec 18 18:53:34 2017 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -31,6 +31,7 @@
 #include "services/heapDumper.hpp"
 #include "services/management.hpp"
 #include "utilities/macros.hpp"
+#include "oops/objArrayOop.hpp"
 
 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
 
@@ -49,6 +50,8 @@
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
+  DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false));
 #if INCLUDE_SERVICES // Heap dumping/inspection supported
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
   DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
@@ -273,6 +276,60 @@
                          vmSymbols::void_method_signature(), CHECK);
 }
 
+void HeapInfoDCmd::execute(DCmdSource source, TRAPS) {
+  Universe::heap()->print_on(output());
+}
+
+void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) {
+  ResourceMark rm;
+
+
+  Klass* k = SystemDictionary::resolve_or_null(
+    vmSymbols::finalizer_histogram_klass(), THREAD);
+  assert(k != NULL, "FinalizerHistogram class is not accessible");
+
+  instanceKlassHandle klass(THREAD, k);
+  JavaValue result(T_ARRAY);
+
+  // We are calling lang.ref.FinalizerHistogram.getFinalizerHistogram() method
+  // and expect it to return array of FinalizerHistogramEntry as Object[]
+
+  JavaCalls::call_static(&result, klass,
+                         vmSymbols::get_finalizer_histogram_name(),
+                         vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK);
+
+  objArrayOop result_oop = (objArrayOop) result.get_jobject();
+  if (result_oop->length() == 0) {
+    output()->print_cr("No instances waiting for finalization found");
+    return;
+  }
+
+  oop foop = result_oop->obj_at(0);
+  InstanceKlass* ik = InstanceKlass::cast(foop->klass());
+
+  fieldDescriptor count_fd, name_fd;
+
+  Klass* count_res = ik->find_field(
+    vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd);
+
+  Klass* name_res = ik->find_field(
+    vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd);
+
+  assert(count_res != NULL && name_res != NULL, "Unexpected layout of FinalizerHistogramEntry");
+
+  output()->print_cr("Unreachable instances waiting for finalization");
+  output()->print_cr("#instances  class name");
+  output()->print_cr("-----------------------");
+
+  for (int i = 0; i < result_oop->length(); ++i) {
+    oop element_oop = result_oop->obj_at(i);
+    oop str_oop = element_oop->obj_field(name_fd.offset());
+    char *name = java_lang_String::as_utf8_string(str_oop);
+    int count = element_oop->int_field(count_fd.offset());
+    output()->print_cr("%10d  %s", count, name);
+  }
+}
+
 #if INCLUDE_SERVICES // Heap dumping/inspection supported
 HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
                            DCmdWithParser(output, heap),
--- a/src/share/vm/services/diagnosticCommand.hpp	Mon Dec 11 02:39:24 2017 -0800
+++ b/src/share/vm/services/diagnosticCommand.hpp	Mon Dec 18 18:53:34 2017 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2017, 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
@@ -176,6 +176,46 @@
     virtual void execute(DCmdSource source, TRAPS);
 };
 
+class HeapInfoDCmd : public DCmd {
+public:
+  HeapInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
+  static const char* name() { return "GC.heap_info"; }
+  static const char* description() {
+    return "Provide generic Java heap information.";
+  }
+  static const char* impact() {
+    return "Medium";
+  }
+  static int num_arguments() { return 0; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+      "monitor", NULL};
+      return p;
+  }
+
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
+class FinalizerInfoDCmd : public DCmd {
+public:
+  FinalizerInfoDCmd(outputStream* output, bool heap) : DCmd(output, heap) { }
+  static const char* name() { return "GC.finalizer_info"; }
+  static const char* description() {
+    return "Provide information about Java finalization queue.";
+  }
+  static const char* impact() {
+    return "Medium";
+  }
+  static int num_arguments() { return 0; }
+  static const JavaPermission permission() {
+    JavaPermission p = {"java.lang.management.ManagementPermission",
+      "monitor", NULL};
+      return p;
+  }
+
+  virtual void execute(DCmdSource source, TRAPS);
+};
+
 #if INCLUDE_SERVICES   // Heap dumping supported
 // See also: dump_heap in attachListener.cpp
 class HeapDumpDCmd : public DCmdWithParser {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/serviceability/dcmd/gc/FinalizerInfoTest.java	Mon Dec 18 18:53:34 2017 -0500
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2017, 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 com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/*
+ * @test
+ * @summary
+ * @library /testlibrary
+ * @run main FinalizerInfoTest
+ */
+public class FinalizerInfoTest {
+    static ReentrantLock lock = new ReentrantLock();
+    static volatile int wasInitialized = 0;
+    static volatile int wasTrapped = 0;
+    static final String cmd = "GC.finalizer_info";
+    static final int objectsCount = 1000;
+
+    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();
+        }
+    }
+
+    void run() throws Exception {
+        try {
+            lock.lock();
+            for(int i = 0; i < objectsCount; ++i) {
+                new MyObject();
+            }
+            System.out.println("Objects initialized: " + objectsCount);
+            System.gc();
+
+            while(wasTrapped < 1) {
+                // Waiting for gc thread.
+            }
+
+
+            String pid = Integer.toString(ProcessTools.getProcessId());
+            ProcessBuilder pb = new ProcessBuilder();
+            pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, cmd});
+            OutputAnalyzer output = new OutputAnalyzer(pb.start());
+            output.shouldContain("MyObject");
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        new  FinalizerInfoTest().run();
+    }
+
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/serviceability/dcmd/gc/HeapInfoTest.java	Mon Dec 18 18:53:34 2017 -0500
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2017, 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 com.oracle.java.testlibrary.JDKToolFinder;
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.heap_info
+ * @library /testlibrary
+ * @run main HeapInfoTest
+ */
+public class HeapInfoTest {
+
+    public static void main(String[] args) throws Exception {
+        String pid = Integer.toString(ProcessTools.getProcessId());
+        ProcessBuilder pb = new ProcessBuilder();
+        pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "GC.heap_info"});
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+        output.shouldContain("Metaspace");
+    }
+}
+