8059036: Implement Diagnostic Commands for heap and finalizerinfo
Summary: Implement Diagnostic Commands for heap and finalizerinfo
Reviewed-by: sla, plevart, mchung
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Wed Jul 29 22:59:03 2015 -0400
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Jul 30 16:26:00 2015 +0300
@@ -568,6 +568,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/hotspot/src/share/vm/services/diagnosticCommand.cpp Wed Jul 29 22:59:03 2015 -0400
+++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp Thu Jul 30 16:26:00 2015 +0300
@@ -37,6 +37,7 @@
#include "services/management.hpp"
#include "services/writeableFlags.hpp"
#include "utilities/macros.hpp"
+#include "oops/objArrayOop.inline.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
@@ -57,6 +58,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));
@@ -333,6 +336,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/hotspot/src/share/vm/services/diagnosticCommand.hpp Wed Jul 29 22:59:03 2015 -0400
+++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp Thu Jul 30 16:26:00 2015 +0300
@@ -241,6 +241,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/hotspot/test/serviceability/dcmd/gc/FinalizerInfoTest.java Thu Jul 30 16:26:00 2015 +0300
@@ -0,0 +1,87 @@
+/*
+ * 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 org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.dcmd.CommandExecutor;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+
+/*
+ * @test
+ * @summary
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @build jdk.test.lib.dcmd.*
+ * @run testng 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();
+ }
+ }
+
+ public void run(CommandExecutor executor) {
+ 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.
+ }
+
+ OutputAnalyzer output = executor.execute(cmd);
+ output.shouldContain("MyObject");
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Test
+ public void pid() {
+ run(new PidJcmdExecutor());
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/serviceability/dcmd/gc/HeapInfoTest.java Thu Jul 30 16:26:00 2015 +0300
@@ -0,0 +1,54 @@
+/*
+ * 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 org.testng.annotations.Test;
+import org.testng.Assert;
+
+import java.io.IOException;
+
+import jdk.test.lib.dcmd.CommandExecutor;
+import jdk.test.lib.dcmd.PidJcmdExecutor;
+import jdk.test.lib.OutputAnalyzer;
+
+
+/*
+ * @test
+ * @summary Test of diagnostic command GC.heap_info
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @build jdk.test.lib.dcmd.*
+ * @run testng HeapInfoTest
+ */
+public class HeapInfoTest {
+ public void run(CommandExecutor executor) {
+ String cmd = "GC.heap_info";
+ OutputAnalyzer output = executor.execute(cmd);
+ output.shouldContain("Metaspace");
+ }
+
+ @Test
+ public void pid() {
+ run(new PidJcmdExecutor());
+ }
+}
+