aboutsummaryrefslogtreecommitdiff
path: root/src/share/demo/management
diff options
context:
space:
mode:
authorduke <none@none>2007-12-01 00:00:00 +0000
committerduke <none@none>2007-12-01 00:00:00 +0000
commit6e45e10b03bafdc125c46a4864ba802c24d6bc78 (patch)
tree182810ab2fece13f57a928d026f93e9ede0827f9 /src/share/demo/management
downloadjdk8u_jdk-6e45e10b03bafdc125c46a4864ba802c24d6bc78.tar.gz
Initial load
Diffstat (limited to 'src/share/demo/management')
-rw-r--r--src/share/demo/management/FullThreadDump/Deadlock.java204
-rw-r--r--src/share/demo/management/FullThreadDump/FullThreadDump.java113
-rw-r--r--src/share/demo/management/FullThreadDump/README.txt52
-rw-r--r--src/share/demo/management/FullThreadDump/ThreadMonitor.java256
-rw-r--r--src/share/demo/management/JTop/JTop.java364
-rw-r--r--src/share/demo/management/JTop/JTopPlugin.java119
-rw-r--r--src/share/demo/management/JTop/META-INF/services/com.sun.tools.jconsole.JConsolePlugin1
-rw-r--r--src/share/demo/management/JTop/README.txt61
-rw-r--r--src/share/demo/management/MemoryMonitor/MemoryMonitor.java463
-rw-r--r--src/share/demo/management/MemoryMonitor/README.txt48
-rw-r--r--src/share/demo/management/VerboseGC/PrintGCStat.java146
-rw-r--r--src/share/demo/management/VerboseGC/README.txt31
-rw-r--r--src/share/demo/management/VerboseGC/VerboseGC.java150
-rw-r--r--src/share/demo/management/index.html46
14 files changed, 2054 insertions, 0 deletions
diff --git a/src/share/demo/management/FullThreadDump/Deadlock.java b/src/share/demo/management/FullThreadDump/Deadlock.java
new file mode 100644
index 0000000000..314750f1b3
--- /dev/null
+++ b/src/share/demo/management/FullThreadDump/Deadlock.java
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.io.IOException;
+
+/**
+ * This Deadlock class demonstrates the capability of performing
+ * deadlock detection programmatically within the application using
+ * the java.lang.management API.
+ *
+ * See ThreadMonitor.java for the use of java.lang.management.ThreadMXBean
+ * API.
+ */
+public class Deadlock {
+ public static void main(String[] argv) {
+ Deadlock dl = new Deadlock();
+
+ // Now find deadlock
+ ThreadMonitor monitor = new ThreadMonitor();
+ boolean found = false;
+ while (!found) {
+ found = monitor.findDeadlock();
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ System.exit(1);
+ }
+ }
+
+ System.out.println("\nPress <Enter> to exit this Deadlock program.\n");
+ waitForEnterPressed();
+ }
+
+
+ private CyclicBarrier barrier = new CyclicBarrier(6);
+ public Deadlock() {
+ DeadlockThread[] dThreads = new DeadlockThread[6];
+
+ Monitor a = new Monitor("a");
+ Monitor b = new Monitor("b");
+ Monitor c = new Monitor("c");
+ dThreads[0] = new DeadlockThread("MThread-1", a, b);
+ dThreads[1] = new DeadlockThread("MThread-2", b, c);
+ dThreads[2] = new DeadlockThread("MThread-3", c, a);
+
+ Lock d = new ReentrantLock();
+ Lock e = new ReentrantLock();
+ Lock f = new ReentrantLock();
+
+ dThreads[3] = new DeadlockThread("SThread-4", d, e);
+ dThreads[4] = new DeadlockThread("SThread-5", e, f);
+ dThreads[5] = new DeadlockThread("SThread-6", f, d);
+
+ // make them daemon threads so that the test will exit
+ for (int i = 0; i < 6; i++) {
+ dThreads[i].setDaemon(true);
+ dThreads[i].start();
+ }
+ }
+
+ class DeadlockThread extends Thread {
+ private Lock lock1 = null;
+ private Lock lock2 = null;
+ private Monitor mon1 = null;
+ private Monitor mon2 = null;
+ private boolean useSync;
+
+ DeadlockThread(String name, Lock lock1, Lock lock2) {
+ super(name);
+ this.lock1 = lock1;
+ this.lock2 = lock2;
+ this.useSync = true;
+ }
+ DeadlockThread(String name, Monitor mon1, Monitor mon2) {
+ super(name);
+ this.mon1 = mon1;
+ this.mon2 = mon2;
+ this.useSync = false;
+ }
+ public void run() {
+ if (useSync) {
+ syncLock();
+ } else {
+ monitorLock();
+ }
+ }
+ private void syncLock() {
+ lock1.lock();
+ try {
+ try {
+ barrier.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ goSyncDeadlock();
+ } finally {
+ lock1.unlock();
+ }
+ }
+ private void goSyncDeadlock() {
+ try {
+ barrier.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ lock2.lock();
+ throw new RuntimeException("should not reach here.");
+ }
+ private void monitorLock() {
+ synchronized (mon1) {
+ try {
+ barrier.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ goMonitorDeadlock();
+ }
+ }
+ private void goMonitorDeadlock() {
+ try {
+ barrier.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ } catch (BrokenBarrierException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ synchronized (mon2) {
+ throw new RuntimeException(getName() + " should not reach here.");
+ }
+ }
+ }
+
+ class Monitor {
+ String name;
+ Monitor(String name) {
+ this.name = name;
+ }
+ }
+
+ private static void waitForEnterPressed() {
+ try {
+ boolean done = false;
+ while (!done) {
+ char ch = (char) System.in.read();
+ if (ch<0||ch=='\n') {
+ done = true;
+ }
+ }
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ System.exit(0);
+ }
+ }
+}
diff --git a/src/share/demo/management/FullThreadDump/FullThreadDump.java b/src/share/demo/management/FullThreadDump/FullThreadDump.java
new file mode 100644
index 0000000000..0b220e0edc
--- /dev/null
+++ b/src/share/demo/management/FullThreadDump/FullThreadDump.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import javax.management.*;
+import javax.management.remote.*;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+/**
+ * This FullThreadDump class demonstrates the capability to get
+ * a full thread dump and also detect deadlock remotely.
+ */
+public class FullThreadDump {
+ private MBeanServerConnection server;
+ private JMXConnector jmxc;
+ public FullThreadDump(String hostname, int port) {
+ System.out.println("Connecting to " + hostname + ":" + port);
+
+ // Create an RMI connector client and connect it to
+ // the RMI connector server
+ String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
+ connect(urlPath);
+ }
+
+ public void dump() {
+ try {
+ ThreadMonitor monitor = new ThreadMonitor(server);
+ monitor.threadDump();
+ if (!monitor.findDeadlock()) {
+ System.out.println("No deadlock found.");
+ }
+ } catch (IOException e) {
+ System.err.println("\nCommunication error: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Connect to a JMX agent of a given URL.
+ */
+ private void connect(String urlPath) {
+ try {
+ JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
+ this.jmxc = JMXConnectorFactory.connect(url);
+ this.server = jmxc.getMBeanServerConnection();
+ } catch (MalformedURLException e) {
+ // should not reach here
+ } catch (IOException e) {
+ System.err.println("\nCommunication error: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ usage();
+ }
+
+ String[] arg2 = args[0].split(":");
+ if (arg2.length != 2) {
+ usage();
+ }
+ String hostname = arg2[0];
+ int port = -1;
+ try {
+ port = Integer.parseInt(arg2[1]);
+ } catch (NumberFormatException x) {
+ usage();
+ }
+ if (port < 0) {
+ usage();
+ }
+
+ // get full thread dump and perform deadlock detection
+ FullThreadDump ftd = new FullThreadDump(hostname, port);
+ ftd.dump();
+ }
+
+ private static void usage() {
+ System.out.println("Usage: java FullThreadDump <hostname>:<port>");
+ }
+}
diff --git a/src/share/demo/management/FullThreadDump/README.txt b/src/share/demo/management/FullThreadDump/README.txt
new file mode 100644
index 0000000000..1571fb8659
--- /dev/null
+++ b/src/share/demo/management/FullThreadDump/README.txt
@@ -0,0 +1,52 @@
+FullThreadDump demonstrates the use of the java.lang.management API
+to print the full thread dump. JDK 6 defines a new API to dump
+the information about monitors and java.util.concurrent ownable
+synchronizers.
+
+This demo also illustrates how to monitor JDK 5 and JDK 6 VMs with
+two versions of APIs.
+
+It contains two parts:
+a) Local monitoring within the application
+b) Remote monitoring by connecting to a JMX agent with a JMX service URL:
+ service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
+ where <hostName> is the hostname and <portNum> is the port number
+ to which the JMX agent will be connected.
+
+To run the demo
+---------------
+a) Local Monitoring
+
+ java -cp <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar Deadlock
+
+ This will dump the stack trace and then detect deadlocks locally
+ within the application.
+
+b) Remote Monitoring
+
+ (1) Start the Deadlock application (or any other application)
+ with the JMX agent as follows:
+
+ java -Dcom.sun.management.jmxremote.port=1090
+ -Dcom.sun.management.jmxremote.ssl=false
+ -Dcom.sun.management.jmxremote.authenticate=false
+ -cp <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar
+ Deadlock
+
+ This instruction uses the Sun's built-in support to enable a JMX agent.
+ You can programmatically start a JMX agent with the RMI connector
+ using javax.management.remote API. See the javadoc and examples for
+ javax.management.remote API for details.
+
+ (2) Run FullThreadDump
+
+ java -jar <JDK_HOME>/demo/management/FullThreadDump/FullThreadDump.jar \
+ localhost:1090
+
+ This will dump the stack trace and then print out the deadlocked threads.
+
+These instructions assume that this installation's version of the java
+command is in your path. If it isn't, then you should either
+specify the complete path to the java command or update your
+PATH environment variable as described in the installation
+instructions for the Java(TM) SDK.
diff --git a/src/share/demo/management/FullThreadDump/ThreadMonitor.java b/src/share/demo/management/FullThreadDump/ThreadMonitor.java
new file mode 100644
index 0000000000..419275ebc2
--- /dev/null
+++ b/src/share/demo/management/FullThreadDump/ThreadMonitor.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2004-2005 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import static java.lang.management.ManagementFactory.*;
+import java.lang.management.ThreadMXBean;
+import java.lang.management.ThreadInfo;
+import java.lang.management.LockInfo;
+import java.lang.management.MonitorInfo;
+import javax.management.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Example of using the java.lang.management API to dump stack trace
+ * and to perform deadlock detection.
+ *
+ * @author Mandy Chung
+ */
+public class ThreadMonitor {
+ private MBeanServerConnection server;
+ private ThreadMXBean tmbean;
+ private ObjectName objname;
+
+ // default - JDK 6+ VM
+ private String findDeadlocksMethodName = "findDeadlockedThreads";
+ private boolean canDumpLocks = true;
+
+ /**
+ * Constructs a ThreadMonitor object to get thread information
+ * in a remote JVM.
+ */
+ public ThreadMonitor(MBeanServerConnection server) throws IOException {
+ this.server = server;
+ this.tmbean = newPlatformMXBeanProxy(server,
+ THREAD_MXBEAN_NAME,
+ ThreadMXBean.class);
+ try {
+ objname = new ObjectName(THREAD_MXBEAN_NAME);
+ } catch (MalformedObjectNameException e) {
+ // should not reach here
+ InternalError ie = new InternalError(e.getMessage());
+ ie.initCause(e);
+ throw ie;
+ }
+ parseMBeanInfo();
+ }
+
+ /**
+ * Constructs a ThreadMonitor object to get thread information
+ * in the local JVM.
+ */
+ public ThreadMonitor() {
+ this.tmbean = getThreadMXBean();
+ }
+
+ /**
+ * Prints the thread dump information to System.out.
+ */
+ public void threadDump() {
+ if (canDumpLocks) {
+ if (tmbean.isObjectMonitorUsageSupported() &&
+ tmbean.isSynchronizerUsageSupported()) {
+ // Print lock info if both object monitor usage
+ // and synchronizer usage are supported.
+ // This sample code can be modified to handle if
+ // either monitor usage or synchronizer usage is supported.
+ dumpThreadInfoWithLocks();
+ }
+ } else {
+ dumpThreadInfo();
+ }
+ }
+
+ private void dumpThreadInfo() {
+ System.out.println("Full Java thread dump");
+ long[] tids = tmbean.getAllThreadIds();
+ ThreadInfo[] tinfos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
+ for (ThreadInfo ti : tinfos) {
+ printThreadInfo(ti);
+ }
+ }
+
+ /**
+ * Prints the thread dump information with locks info to System.out.
+ */
+ private void dumpThreadInfoWithLocks() {
+ System.out.println("Full Java thread dump with locks info");
+
+ ThreadInfo[] tinfos = tmbean.dumpAllThreads(true, true);
+ for (ThreadInfo ti : tinfos) {
+ printThreadInfo(ti);
+ LockInfo[] syncs = ti.getLockedSynchronizers();
+ printLockInfo(syncs);
+ }
+ System.out.println();
+ }
+
+ private static String INDENT = " ";
+
+ private void printThreadInfo(ThreadInfo ti) {
+ // print thread information
+ printThread(ti);
+
+ // print stack trace with locks
+ StackTraceElement[] stacktrace = ti.getStackTrace();
+ MonitorInfo[] monitors = ti.getLockedMonitors();
+ for (int i = 0; i < stacktrace.length; i++) {
+ StackTraceElement ste = stacktrace[i];
+ System.out.println(INDENT + "at " + ste.toString());
+ for (MonitorInfo mi : monitors) {
+ if (mi.getLockedStackDepth() == i) {
+ System.out.println(INDENT + " - locked " + mi);
+ }
+ }
+ }
+ System.out.println();
+ }
+
+ private void printThread(ThreadInfo ti) {
+ StringBuilder sb = new StringBuilder("\"" + ti.getThreadName() + "\"" +
+ " Id=" + ti.getThreadId() +
+ " in " + ti.getThreadState());
+ if (ti.getLockName() != null) {
+ sb.append(" on lock=" + ti.getLockName());
+ }
+ if (ti.isSuspended()) {
+ sb.append(" (suspended)");
+ }
+ if (ti.isInNative()) {
+ sb.append(" (running in native)");
+ }
+ System.out.println(sb.toString());
+ if (ti.getLockOwnerName() != null) {
+ System.out.println(INDENT + " owned by " + ti.getLockOwnerName() +
+ " Id=" + ti.getLockOwnerId());
+ }
+ }
+
+ private void printMonitorInfo(ThreadInfo ti, MonitorInfo[] monitors) {
+ System.out.println(INDENT + "Locked monitors: count = " + monitors.length);
+ for (MonitorInfo mi : monitors) {
+ System.out.println(INDENT + " - " + mi + " locked at ");
+ System.out.println(INDENT + " " + mi.getLockedStackDepth() +
+ " " + mi.getLockedStackFrame());
+ }
+ }
+
+ private void printLockInfo(LockInfo[] locks) {
+ System.out.println(INDENT + "Locked synchronizers: count = " + locks.length);
+ for (LockInfo li : locks) {
+ System.out.println(INDENT + " - " + li);
+ }
+ System.out.println();
+ }
+
+ /**
+ * Checks if any threads are deadlocked. If any, print
+ * the thread dump information.
+ */
+ public boolean findDeadlock() {
+ long[] tids;
+ if (findDeadlocksMethodName.equals("findDeadlockedThreads") &&
+ tmbean.isSynchronizerUsageSupported()) {
+ tids = tmbean.findDeadlockedThreads();
+ if (tids == null) {
+ return false;
+ }
+
+ System.out.println("Deadlock found :-");
+ ThreadInfo[] infos = tmbean.getThreadInfo(tids, true, true);
+ for (ThreadInfo ti : infos) {
+ printThreadInfo(ti);
+ printLockInfo(ti.getLockedSynchronizers());
+ System.out.println();
+ }
+ } else {
+ tids = tmbean.findMonitorDeadlockedThreads();
+ if (tids == null) {
+ return false;
+ }
+ ThreadInfo[] infos = tmbean.getThreadInfo(tids, Integer.MAX_VALUE);
+ for (ThreadInfo ti : infos) {
+ // print thread information
+ printThreadInfo(ti);
+ }
+ }
+
+ return true;
+ }
+
+
+ private void parseMBeanInfo() throws IOException {
+ try {
+ MBeanOperationInfo[] mopis = server.getMBeanInfo(objname).getOperations();
+
+ // look for findDeadlockedThreads operations;
+ boolean found = false;
+ for (MBeanOperationInfo op : mopis) {
+ if (op.getName().equals(findDeadlocksMethodName)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ // if findDeadlockedThreads operation doesn't exist,
+ // the target VM is running on JDK 5 and details about
+ // synchronizers and locks cannot be dumped.
+ findDeadlocksMethodName = "findMonitorDeadlockedThreads";
+ canDumpLocks = false;
+ }
+ } catch (IntrospectionException e) {
+ InternalError ie = new InternalError(e.getMessage());
+ ie.initCause(e);
+ throw ie;
+ } catch (InstanceNotFoundException e) {
+ InternalError ie = new InternalError(e.getMessage());
+ ie.initCause(e);
+ throw ie;
+ } catch (ReflectionException e) {
+ InternalError ie = new InternalError(e.getMessage());
+ ie.initCause(e);
+ throw ie;
+ }
+ }
+}
diff --git a/src/share/demo/management/JTop/JTop.java b/src/share/demo/management/JTop/JTop.java
new file mode 100644
index 0000000000..121b159762
--- /dev/null
+++ b/src/share/demo/management/JTop/JTop.java
@@ -0,0 +1,364 @@
+/*
+ * Copyright 2005-2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *
+ * Example of using the java.lang.management API to sort threads
+ * by CPU usage.
+ *
+ * JTop class can be run as a standalone application.
+ * It first establishs a connection to a target VM specified
+ * by the given hostname and port number where the JMX agent
+ * to be connected. It then polls for the thread information
+ * and the CPU consumption of each thread to display every 2
+ * seconds.
+ *
+ * It is also used by JTopPlugin which is a JConsolePlugin
+ * that can be used with JConsole (see README.txt). The JTop
+ * GUI will be added as a JConsole tab by the JTop plugin.
+ *
+ * @see com.sun.tools.jconsole.JConsolePlugin
+ *
+ * @author Mandy Chung
+ */
+import java.lang.management.*;
+import javax.management.*;
+import javax.management.remote.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.TreeMap;
+import java.util.concurrent.ExecutionException;
+import java.text.NumberFormat;
+import java.net.MalformedURLException;
+import static java.lang.management.ManagementFactory.*;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+
+/**
+ * JTop is a JPanel to display thread's name, CPU time, and its state
+ * in a table.
+ */
+public class JTop extends JPanel {
+ private MBeanServerConnection server;
+ private ThreadMXBean tmbean;
+ private MyTableModel tmodel;
+ public JTop() {
+ super(new GridLayout(1,0));
+
+ tmodel = new MyTableModel();
+ JTable table = new JTable(tmodel);
+ table.setPreferredScrollableViewportSize(new Dimension(500, 300));
+
+ // Set the renderer to format Double
+ table.setDefaultRenderer(Double.class, new DoubleRenderer());
+ // Add some space
+ table.setIntercellSpacing(new Dimension(6,3));
+ table.setRowHeight(table.getRowHeight() + 4);
+
+ // Create the scroll pane and add the table to it.
+ JScrollPane scrollPane = new JScrollPane(table);
+
+ // Add the scroll pane to this panel.
+ add(scrollPane);
+ }
+
+ // Set the MBeanServerConnection object for communicating
+ // with the target VM
+ public void setMBeanServerConnection(MBeanServerConnection mbs) {
+ this.server = mbs;
+ try {
+ this.tmbean = newPlatformMXBeanProxy(server,
+ THREAD_MXBEAN_NAME,
+ ThreadMXBean.class);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (!tmbean.isThreadCpuTimeSupported()) {
+ System.err.println("This VM does not support thread CPU time monitoring");
+ } else {
+ tmbean.setThreadCpuTimeEnabled(true);
+ }
+ }
+
+ class MyTableModel extends AbstractTableModel {
+ private String[] columnNames = {"ThreadName",
+ "CPU(sec)",
+ "State"};
+ // List of all threads. The key of each entry is the CPU time
+ // and its value is the ThreadInfo object with no stack trace.
+ private List<Map.Entry<Long, ThreadInfo>> threadList =
+ Collections.EMPTY_LIST;
+
+ public MyTableModel() {
+ }
+
+ public int getColumnCount() {
+ return columnNames.length;
+ }
+
+ public int getRowCount() {
+ return threadList.size();
+ }
+
+ public String getColumnName(int col) {
+ return columnNames[col];
+ }
+
+ public Object getValueAt(int row, int col) {
+ Map.Entry<Long, ThreadInfo> me = threadList.get(row);
+ switch (col) {
+ case 0 :
+ // Column 0 shows the thread name
+ return me.getValue().getThreadName();
+ case 1 :
+ // Column 1 shows the CPU usage
+ long ns = me.getKey().longValue();
+ double sec = ns / 1000000000;
+ return new Double(sec);
+ case 2 :
+ // Column 2 shows the thread state
+ return me.getValue().getThreadState();
+ default:
+ return null;
+ }
+ }
+
+ public Class getColumnClass(int c) {
+ return getValueAt(0, c).getClass();
+ }
+
+ void setThreadList(List<Map.Entry<Long, ThreadInfo>> list) {
+ threadList = list;
+ }
+ }
+
+ /**
+ * Get the thread list with CPU consumption and the ThreadInfo
+ * for each thread sorted by the CPU time.
+ */
+ private List<Map.Entry<Long, ThreadInfo>> getThreadList() {
+ // Get all threads and their ThreadInfo objects
+ // with no stack trace
+ long[] tids = tmbean.getAllThreadIds();
+ ThreadInfo[] tinfos = tmbean.getThreadInfo(tids);
+
+ // build a map with key = CPU time and value = ThreadInfo
+ SortedMap<Long, ThreadInfo> map = new TreeMap<Long, ThreadInfo>();
+ for (int i = 0; i < tids.length; i++) {
+ long cpuTime = tmbean.getThreadCpuTime(tids[i]);
+ // filter out threads that have been terminated
+ if (cpuTime != -1 && tinfos[i] != null) {
+ map.put(new Long(cpuTime), tinfos[i]);
+ }
+ }
+
+ // build the thread list and sort it with CPU time
+ // in decreasing order
+ Set<Map.Entry<Long, ThreadInfo>> set = map.entrySet();
+ List<Map.Entry<Long, ThreadInfo>> list =
+ new ArrayList<Map.Entry<Long, ThreadInfo>>(set);
+ Collections.reverse(list);
+ return list;
+ }
+
+
+ /**
+ * Format Double with 4 fraction digits
+ */
+ class DoubleRenderer extends DefaultTableCellRenderer {
+ NumberFormat formatter;
+ public DoubleRenderer() {
+ super();
+ setHorizontalAlignment(JLabel.RIGHT);
+ }
+
+ public void setValue(Object value) {
+ if (formatter==null) {
+ formatter = NumberFormat.getInstance();
+ formatter.setMinimumFractionDigits(4);
+ }
+ setText((value == null) ? "" : formatter.format(value));
+ }
+ }
+
+ // SwingWorker responsible for updating the GUI
+ //
+ // It first gets the thread and CPU usage information as a
+ // background task done by a worker thread so that
+ // it will not block the event dispatcher thread.
+ //
+ // When the worker thread finishes, the event dispatcher
+ // thread will invoke the done() method which will update
+ // the UI.
+ class Worker extends SwingWorker<List<Map.Entry<Long, ThreadInfo>>,Object> {
+ private MyTableModel tmodel;
+ Worker(MyTableModel tmodel) {
+ this.tmodel = tmodel;
+ }
+
+ // Get the current thread info and CPU time
+ public List<Map.Entry<Long, ThreadInfo>> doInBackground() {
+ return getThreadList();
+ }
+
+ // fire table data changed to trigger GUI update
+ // when doInBackground() is finished
+ protected void done() {
+ try {
+ // Set table model with the new thread list
+ tmodel.setThreadList(get());
+ // refresh the table model
+ tmodel.fireTableDataChanged();
+ } catch (InterruptedException e) {
+ } catch (ExecutionException e) {
+ }
+ }
+ }
+
+ // Return a new SwingWorker for UI update
+ public SwingWorker<?,?> newSwingWorker() {
+ return new Worker(tmodel);
+ }
+
+ public static void main(String[] args) throws Exception {
+ // Validate the input arguments
+ if (args.length != 1) {
+ usage();
+ }
+
+ String[] arg2 = args[0].split(":");
+ if (arg2.length != 2) {
+ usage();
+ }
+ String hostname = arg2[0];
+ int port = -1;
+ try {
+ port = Integer.parseInt(arg2[1]);
+ } catch (NumberFormatException x) {
+ usage();
+ }
+ if (port < 0) {
+ usage();
+ }
+
+ // Create the JTop Panel
+ final JTop jtop = new JTop();
+ // Set up the MBeanServerConnection to the target VM
+ MBeanServerConnection server = connect(hostname, port);
+ jtop.setMBeanServerConnection(server);
+
+ // A timer task to update GUI per each interval
+ TimerTask timerTask = new TimerTask() {
+ public void run() {
+ // Schedule the SwingWorker to update the GUI
+ jtop.newSwingWorker().execute();
+ }
+ };
+
+ // Create the standalone window with JTop panel
+ // by the event dispatcher thread
+ SwingUtilities.invokeAndWait(new Runnable() {
+ public void run() {
+ createAndShowGUI(jtop);
+ }
+ });
+
+ // refresh every 2 seconds
+ Timer timer = new Timer("JTop Sampling thread");
+ timer.schedule(timerTask, 0, 2000);
+
+ }
+
+ // Establish a connection with the remote application
+ //
+ // You can modify the urlPath to the address of the JMX agent
+ // of your application if it has a different URL.
+ //
+ // You can also modify the following code to take
+ // username and password for client authentication.
+ private static MBeanServerConnection connect(String hostname, int port) {
+ // Create an RMI connector client and connect it to
+ // the RMI connector server
+ String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
+ MBeanServerConnection server = null;
+ try {
+ JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
+ JMXConnector jmxc = JMXConnectorFactory.connect(url);
+ server = jmxc.getMBeanServerConnection();
+ } catch (MalformedURLException e) {
+ // should not reach here
+ } catch (IOException e) {
+ System.err.println("\nCommunication error: " + e.getMessage());
+ System.exit(1);
+ }
+ return server;
+ }
+
+ private static void usage() {
+ System.out.println("Usage: java JTop <hostname>:<port>");
+ System.exit(1);
+ }
+ /**
+ * Create the GUI and show it. For thread safety,
+ * this method should be invoked from the
+ * event-dispatching thread.
+ */
+ private static void createAndShowGUI(JPanel jtop) {
+ // Create and set up the window.
+ JFrame frame = new JFrame("JTop");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ // Create and set up the content pane.
+ JComponent contentPane = (JComponent) frame.getContentPane();
+ contentPane.add(jtop, BorderLayout.CENTER);
+ contentPane.setOpaque(true); //content panes must be opaque
+ contentPane.setBorder(new EmptyBorder(12, 12, 12, 12));
+ frame.setContentPane(contentPane);
+
+ // Display the window.
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+}
diff --git a/src/share/demo/management/JTop/JTopPlugin.java b/src/share/demo/management/JTop/JTopPlugin.java
new file mode 100644
index 0000000000..44866af34a
--- /dev/null
+++ b/src/share/demo/management/JTop/JTopPlugin.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ *
+ * Example of a JConsole Plugin. This loads JTop as a JConsole tab.
+ *
+ * @author Mandy Chung
+ */
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.management.MBeanServerConnection;
+import javax.swing.JPanel;
+import javax.swing.SwingWorker;
+
+import com.sun.tools.jconsole.JConsolePlugin;
+import com.sun.tools.jconsole.JConsoleContext;
+import com.sun.tools.jconsole.JConsoleContext.ConnectionState;
+
+/**
+ * JTopPlugin is a subclass to com.sun.tools.jconsole.JConsolePlugin
+ *
+ * JTopPlugin is loaded and instantiated by JConsole. One instance
+ * is created for each window that JConsole creates. It listens to
+ * the connected property change so that it will update JTop with
+ * the valid MBeanServerConnection object. JTop is a JPanel object
+ * displaying the thread and its CPU usage information.
+ */
+public class JTopPlugin extends JConsolePlugin implements PropertyChangeListener
+{
+ private JTop jtop = null;
+ private Map<String, JPanel> tabs = null;
+
+ public JTopPlugin() {
+ // register itself as a listener
+ addContextPropertyChangeListener(this);
+ }
+
+ /*
+ * Returns a JTop tab to be added in JConsole.
+ */
+ public synchronized Map<String, JPanel> getTabs() {
+ if (tabs == null) {
+ jtop = new JTop();
+ jtop.setMBeanServerConnection(
+ getContext().getMBeanServerConnection());
+ // use LinkedHashMap if you want a predictable order
+ // of the tabs to be added in JConsole
+ tabs = new LinkedHashMap<String, JPanel>();
+ tabs.put("JTop", jtop);
+ }
+ return tabs;
+ }
+
+ /*
+ * Returns a SwingWorker which is responsible for updating the JTop tab.
+ */
+ public SwingWorker<?,?> newSwingWorker() {
+ return jtop.newSwingWorker();
+ }
+
+ // You can implement the dispose() method if you need to release
+ // any resource when the plugin instance is disposed when the JConsole
+ // window is closed.
+ //
+ // public void dispose() {
+ // }
+
+ /*
+ * Property listener to reset the MBeanServerConnection
+ * at reconnection time.
+ */
+ public void propertyChange(PropertyChangeEvent ev) {
+ String prop = ev.getPropertyName();
+ if (prop == JConsoleContext.CONNECTION_STATE_PROPERTY) {
+ ConnectionState oldState = (ConnectionState)ev.getOldValue();
+ ConnectionState newState = (ConnectionState)ev.getNewValue();
+ // JConsole supports disconnection and reconnection
+ // The MBeanServerConnection will become invalid when
+ // disconnected. Need to use the new MBeanServerConnection object
+ // created at reconnection time.
+ if (newState == ConnectionState.CONNECTED && jtop != null) {
+ jtop.setMBeanServerConnection(
+ getContext().getMBeanServerConnection());
+ }
+ }
+ }
+}
diff --git a/src/share/demo/management/JTop/META-INF/services/com.sun.tools.jconsole.JConsolePlugin b/src/share/demo/management/JTop/META-INF/services/com.sun.tools.jconsole.JConsolePlugin
new file mode 100644
index 0000000000..11aa2aea38
--- /dev/null
+++ b/src/share/demo/management/JTop/META-INF/services/com.sun.tools.jconsole.JConsolePlugin
@@ -0,0 +1 @@
+JTopPlugin
diff --git a/src/share/demo/management/JTop/README.txt b/src/share/demo/management/JTop/README.txt
new file mode 100644
index 0000000000..b2d3ae43c0
--- /dev/null
+++ b/src/share/demo/management/JTop/README.txt
@@ -0,0 +1,61 @@
+JTop monitors the CPU usage of all threads in a remote application
+which has remote management enabled. JTop demonstrates the use of
+the java.lang.management API to obtain the CPU consumption for
+each thread.
+
+JTop is also a JConsole Plugin. See below for details.
+
+JTop Standalone GUI
+===================
+
+JTop first establishes a connection to a JMX agent in a remote
+application with a JMX service URL:
+ service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
+
+where <hostName> is the hostname and <portNum> is the port number
+to which the JMX agent will be connected.
+
+To run the demo
+---------------
+(1) Start the application with the JMX agent - here's an example of
+ how the Java2D is started
+
+ java -Dcom.sun.management.jmxremote.port=1090
+ -Dcom.sun.management.jmxremote.ssl=false
+ -Dcom.sun.management.jmxremote.authenticate=false
+ -jar <JDK_HOME>/demo/jfc/Java2D/Java2Demo.jar
+
+ This instruction uses the Sun's built-in support to enable a JMX agent
+ with a JMX service URL as described above.
+ You can programmatically start a JMX agent with the RMI connector
+ using javax.management.remote API. See the javadoc and examples for
+ javax.management.remote API for details.
+
+(2) Run JTop on a different machine:
+
+ java -jar <JDK_HOME>/demo/management/JTop/JTop.jar <hostname>:1090
+
+ where <hostname> is where the Java2Demo.jar runs in step (1).
+
+These instructions assume that this installation's version of the java
+command is in your path. If it isn't, then you should either
+specify the complete path to the java command or update your
+PATH environment variable as described in the installation
+instructions for the Java(TM) SDK.
+
+JTop JConsole Plugin
+====================
+
+JTop is a JConsole Plugin which adds a "JTop" tab to JConsole.
+
+To run JConsole with the JTop plugin
+------------------------------------
+ jconsole -pluginpath <JDK_HOME>/demo/management/JTop/JTop.jar
+
+
+To compile
+----------
+ javac -classpath <JDK_HOME>/lib/jconsole.jar JTopPlugin.java
+
+com.sun.tools.jconsole API is in jconsole.jar which is needed
+in the classpath for compilation.
diff --git a/src/share/demo/management/MemoryMonitor/MemoryMonitor.java b/src/share/demo/management/MemoryMonitor/MemoryMonitor.java
new file mode 100644
index 0000000000..c44e5f2c2d
--- /dev/null
+++ b/src/share/demo/management/MemoryMonitor/MemoryMonitor.java
@@ -0,0 +1,463 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.BufferedImage;
+import java.awt.geom.Line2D;
+import java.awt.geom.Rectangle2D;
+import java.util.Date;
+import javax.swing.*;
+import javax.swing.border.EtchedBorder;
+import javax.swing.border.TitledBorder;
+import java.lang.management.*;
+import java.util.*;
+
+
+/**
+ * Demo code which plots the memory usage by all memory pools.
+ * The memory usage is sampled at some time interval using
+ * java.lang.management API. This demo code is modified based
+ * java2d MemoryMonitor demo.
+ */
+public class MemoryMonitor extends JPanel {
+
+ static JCheckBox dateStampCB = new JCheckBox("Output Date Stamp");
+ public Surface surf;
+ JPanel controls;
+ boolean doControls;
+ JTextField tf;
+ // Get memory pools.
+ static java.util.List<MemoryPoolMXBean> mpools =
+ ManagementFactory.getMemoryPoolMXBeans();
+ // Total number of memory pools.
+ static int numPools = mpools.size();
+
+ public MemoryMonitor() {
+ setLayout(new BorderLayout());
+ setBorder(new TitledBorder(new EtchedBorder(), "Memory Monitor"));
+ add(surf = new Surface());
+ controls = new JPanel();
+ controls.setPreferredSize(new Dimension(135,80));
+ Font font = new Font("serif", Font.PLAIN, 10);
+ JLabel label = new JLabel("Sample Rate");
+ label.setFont(font);
+ label.setForeground(Color.red);
+ controls.add(label);
+ tf = new JTextField("1000");
+ tf.setPreferredSize(new Dimension(45,20));
+ controls.add(tf);
+ controls.add(label = new JLabel("ms"));
+ label.setFont(font);
+ label.setForeground(Color.red);
+ controls.add(dateStampCB);
+ dateStampCB.setFont(font);
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ removeAll();
+ if ((doControls = !doControls)) {
+ surf.stop();
+ add(controls);
+ } else {
+ try {
+ surf.sleepAmount = Long.parseLong(tf.getText().trim());
+ } catch (Exception ex) {}
+ surf.start();
+ add(surf);
+ }
+ validate();
+ repaint();
+ }
+ });
+ }
+
+
+ public class Surface extends JPanel implements Runnable {
+
+ public Thread thread;
+ public long sleepAmount = 1000;
+ public int usageHistCount = 20000;
+ private int w, h;
+ private BufferedImage bimg;
+ private Graphics2D big;
+ private Font font = new Font("Times New Roman", Font.PLAIN, 11);
+ private int columnInc;
+ private float usedMem[][];
+ private int ptNum[];
+ private int ascent, descent;
+ private Rectangle graphOutlineRect = new Rectangle();
+ private Rectangle2D mfRect = new Rectangle2D.Float();
+ private Rectangle2D muRect = new Rectangle2D.Float();
+ private Line2D graphLine = new Line2D.Float();
+ private Color graphColor = new Color(46, 139, 87);
+ private Color mfColor = new Color(0, 100, 0);
+ private String usedStr;
+
+
+ public Surface() {
+ setBackground(Color.black);
+ addMouseListener(new MouseAdapter() {
+ public void mouseClicked(MouseEvent e) {
+ if (thread == null) start(); else stop();
+ }
+ });
+ int i = 0;
+ usedMem = new float[numPools][];
+ ptNum = new int[numPools];
+ }
+
+ public Dimension getMinimumSize() {
+ return getPreferredSize();
+ }
+
+ public Dimension getMaximumSize() {
+ return getPreferredSize();
+ }
+
+ public Dimension getPreferredSize() {
+ return new Dimension(135,80);
+ }
+
+
+ public void paint(Graphics g) {
+
+ if (big == null) {
+ return;
+ }
+
+ big.setBackground(getBackground());
+ big.clearRect(0,0,w,h);
+
+
+ h = h / ((numPools + numPools%2) / 2);
+ w = w / 2;
+
+ int k=0; // index of memory pool.
+ for (int i=0; i < 2;i++) {
+ for (int j=0; j < (numPools + numPools%2)/ 2; j++) {
+ plotMemoryUsage(w*i,h*j,w,h,k);
+ if (++k >= numPools) {
+ i = 3;
+ j = (numPools + numPools%2)/ 2;
+ break;
+ }
+ }
+ }
+ g.drawImage(bimg, 0, 0, this);
+ }
+
+ public void plotMemoryUsage(int x1, int y1, int x2, int y2, int npool) {
+
+ MemoryPoolMXBean mp = mpools.get(npool);
+ float usedMemory = mp.getUsage().getUsed();
+ float totalMemory = mp.getUsage().getMax();
+
+ // .. Draw allocated and used strings ..
+ big.setColor(Color.green);
+
+ // Print Max memory allocated for this memory pool.
+ big.drawString(String.valueOf((int)totalMemory/1024) + "K Max ", x1+4.0f, (float) y1 + ascent+0.5f);
+ big.setColor(Color.yellow);
+
+ // Print the memory pool name.
+ big.drawString(mp.getName(), x1+x2/2, (float) y1 + ascent+0.5f);
+
+ // Print the memory used by this memory pool.
+ usedStr = String.valueOf((int)usedMemory/1024)
+ + "K used";
+ big.setColor(Color.green);
+ big.drawString(usedStr, x1+4, y1+y2-descent);
+
+ // Calculate remaining size
+ float ssH = ascent + descent;
+ float remainingHeight = (float) (y2 - (ssH*2) - 0.5f);
+ float blockHeight = remainingHeight/10;
+ float blockWidth = 20.0f;
+ float remainingWidth = (float) (x2 - blockWidth - 10);
+
+ // .. Memory Free ..
+ big.setColor(mfColor);
+ int MemUsage = (int) (((totalMemory - usedMemory) / totalMemory) * 10);
+ int i = 0;
+ for ( ; i < MemUsage ; i++) {
+ mfRect.setRect(x1+5,(float) y1+ssH+i*blockHeight,
+ blockWidth,(float) blockHeight-1);
+ big.fill(mfRect);
+ }
+
+ // .. Memory Used ..
+ big.setColor(Color.green);
+ for ( ; i < 10; i++) {
+ muRect.setRect(x1+5,(float) y1 + ssH+i*blockHeight,
+ blockWidth,(float) blockHeight-1);
+ big.fill(muRect);
+ }
+
+ // .. Draw History Graph ..
+ if (remainingWidth <= 30) remainingWidth = (float)30;
+ if (remainingHeight <= ssH) remainingHeight = (float)ssH;
+ big.setColor(graphColor);
+ int graphX = x1+30;
+ int graphY = y1 + (int) ssH;
+ int graphW = (int) remainingWidth;
+ int graphH = (int) remainingHeight;
+
+ graphOutlineRect.setRect(graphX, graphY, graphW, graphH);
+ big.draw(graphOutlineRect);
+
+ int graphRow = graphH/10;
+
+ // .. Draw row ..
+ for (int j = graphY; j <= graphH+graphY; j += graphRow) {
+ graphLine.setLine(graphX,j,graphX+graphW,j);
+ big.draw(graphLine);
+ }
+
+ // .. Draw animated column movement ..
+ int graphColumn = graphW/15;
+
+ if (columnInc == 0) {
+ columnInc = graphColumn;
+ }
+
+ for (int j = graphX+columnInc; j < graphW+graphX; j+=graphColumn) {
+ graphLine.setLine(j,graphY,j,graphY+graphH);
+ big.draw(graphLine);
+ }
+
+ --columnInc;
+
+ // Plot memory usage by this memory pool.
+ if (usedMem[npool] == null) {
+ usedMem[npool] = new float[usageHistCount];
+ ptNum[npool] = 0;
+ }
+
+ // save memory usage history.
+ usedMem[npool][ptNum[npool]] = usedMemory;
+
+ big.setColor(Color.yellow);
+
+ int w1; // width of memory usage history.
+ if (ptNum[npool] > graphW) {
+ w1 = graphW;
+ } else {
+ w1 = ptNum[npool];
+ }
+
+
+ for (int j=graphX+graphW-w1, k=ptNum[npool]-w1; k < ptNum[npool];
+ k++, j++) {
+ if (k != 0) {
+ if (usedMem[npool][k] != usedMem[npool][k-1]) {
+ int h1 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k-1])/totalMemory));
+ int h2 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k])/totalMemory));
+ big.drawLine(j-1, h1, j, h2);
+ } else {
+ int h1 = (int)(graphY + graphH * ((totalMemory -usedMem[npool][k])/totalMemory));
+ big.fillRect(j, h1, 1, 1);
+ }
+ }
+ }
+ if (ptNum[npool]+2 == usedMem[npool].length) {
+ // throw out oldest point
+ for (int j = 1;j < ptNum[npool]; j++) {
+ usedMem[npool][j-1] = usedMem[npool][j];
+ }
+ --ptNum[npool];
+ } else {
+ ptNum[npool]++;
+ }
+ }
+
+
+ public void start() {
+ thread = new Thread(this);
+ thread.setPriority(Thread.MIN_PRIORITY);
+ thread.setName("MemoryMonitor");
+ thread.start();
+ }
+
+
+ public synchronized void stop() {
+ thread = null;
+ notify();
+ }
+
+ public void run() {
+
+ Thread me = Thread.currentThread();
+
+ while (thread == me && !isShowing() || getSize().width == 0) {
+ try {
+ thread.sleep(500);
+ } catch (InterruptedException e) { return; }
+ }
+
+ while (thread == me && isShowing()) {
+ Dimension d = getSize();
+ if (d.width != w || d.height != h) {
+ w = d.width;
+ h = d.height;
+ bimg = (BufferedImage) createImage(w, h);
+ big = bimg.createGraphics();
+ big.setFont(font);
+ FontMetrics fm = big.getFontMetrics(font);
+ ascent = (int) fm.getAscent();
+ descent = (int) fm.getDescent();
+ }
+ repaint();
+ try {
+ thread.sleep(sleepAmount);
+ } catch (InterruptedException e) { break; }
+ if (MemoryMonitor.dateStampCB.isSelected()) {
+ System.out.println(new Date().toString() + " " + usedStr);
+ }
+ }
+ thread = null;
+ }
+ }
+
+
+ // Test thread to consume memory
+ static class Memeater extends ClassLoader implements Runnable {
+ Object y[];
+ public Memeater() {}
+ public void run() {
+ y = new Object[10000000];
+ int k =0;
+ while(true) {
+ if (k == 5000000) k=0;
+ y[k++] = new Object();
+ try {
+ Thread.sleep(20);
+ } catch (Exception x){}
+
+ // to consume perm gen storage
+ try {
+ // the classes are small so we load 10 at a time
+ for (int i=0; i<10; i++) {
+ loadNext();
+ }
+ } catch (ClassNotFoundException x) {
+ // ignore exception
+ }
+
+ }
+
+ }
+
+ Class loadNext() throws ClassNotFoundException {
+
+ // public class TestNNNNNN extends java.lang.Object{
+ // public TestNNNNNN();
+ // Code:
+ // 0: aload_0
+ // 1: invokespecial #1; //Method java/lang/Object."<init>":()V
+ // 4: return
+ // }
+
+ int begin[] = {
+ 0xca, 0xfe, 0xba, 0xbe, 0x00, 0x00, 0x00, 0x30,
+ 0x00, 0x0a, 0x0a, 0x00, 0x03, 0x00, 0x07, 0x07,
+ 0x00, 0x08, 0x07, 0x00, 0x09, 0x01, 0x00, 0x06,
+ 0x3c, 0x69, 0x6e, 0x69, 0x74, 0x3e, 0x01, 0x00,
+ 0x03, 0x28, 0x29, 0x56, 0x01, 0x00, 0x04, 0x43,
+ 0x6f, 0x64, 0x65, 0x0c, 0x00, 0x04, 0x00, 0x05,
+ 0x01, 0x00, 0x0a, 0x54, 0x65, 0x73, 0x74 };
+
+ int end [] = {
+ 0x01, 0x00, 0x10,
+ 0x6a, 0x61, 0x76, 0x61, 0x2f, 0x6c, 0x61, 0x6e,
+ 0x67, 0x2f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74,
+ 0x00, 0x21, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x04,
+ 0x00, 0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00,
+ 0x00, 0x11, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0x00, 0x05, 0x2a, 0xb7, 0x00, 0x01, 0xb1, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+
+ // TestNNNNNN
+
+ String name = "Test" + Integer.toString(count++);
+
+ byte value[];
+ try {
+ value = name.substring(4).getBytes("UTF-8");
+ } catch (java.io.UnsupportedEncodingException x) {
+ throw new Error();
+ }
+
+ // construct class file
+
+ int len = begin.length + value.length + end.length;
+ byte b[] = new byte[len];
+ int i, pos=0;
+ for (i=0; i<begin.length; i++) {
+ b[pos++] = (byte)begin[i];
+ }
+ for (i=0; i<value.length; i++) {
+ b[pos++] = value[i];
+ }
+ for (i=0; i<end.length; i++) {
+ b[pos++] = (byte)end[i];
+ }
+
+ return defineClass(name, b, 0, b.length);
+
+ }
+ static int count = 100000;
+
+ }
+
+ public static void main(String s[]) {
+ final MemoryMonitor demo = new MemoryMonitor();
+ WindowListener l = new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {System.exit(0);}
+ public void windowDeiconified(WindowEvent e) { demo.surf.start(); }
+ public void windowIconified(WindowEvent e) { demo.surf.stop(); }
+ };
+ JFrame f = new JFrame("MemoryMonitor");
+ f.addWindowListener(l);
+ f.getContentPane().add("Center", demo);
+ f.pack();
+ f.setSize(new Dimension(400,500));
+ f.setVisible(true);
+ demo.surf.start();
+ Thread thr = new Thread(new Memeater());
+ thr.start();
+ }
+
+}
diff --git a/src/share/demo/management/MemoryMonitor/README.txt b/src/share/demo/management/MemoryMonitor/README.txt
new file mode 100644
index 0000000000..4133bab29c
--- /dev/null
+++ b/src/share/demo/management/MemoryMonitor/README.txt
@@ -0,0 +1,48 @@
+#
+# Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# - Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# - Neither the name of Sun Microsystems nor the names of its
+# contributors may be used to endorse or promote products derived
+# from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+MemoryMonitor demonstrates the use of the java.lang.management API
+in observing the memory usage of all memory pools consumed by
+the application.
+
+This simple demo program queries the memory usage of each memory pool
+and plots the memory usage history graph.
+
+To run the MemoryMonitor demo
+
+ java -jar <JDK_HOME>/demo/management/MemoryMonitor.jar
+
+These instructions assume that this installation's version of the java
+command is in your path. If it isn't, then you should either
+specify the complete path to the java command or update your
+PATH environment variable as described in the installation
+instructions for the Java(TM) SDK.
+
diff --git a/src/share/demo/management/VerboseGC/PrintGCStat.java b/src/share/demo/management/VerboseGC/PrintGCStat.java
new file mode 100644
index 0000000000..5ac52d77d2
--- /dev/null
+++ b/src/share/demo/management/VerboseGC/PrintGCStat.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import static java.lang.management.ManagementFactory.*;
+import java.lang.management.*;
+import javax.management.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * Example of using the java.lang.management API to monitor
+ * the memory usage and garbage collection statistics.
+ *
+ * @author Mandy Chung
+ */
+public class PrintGCStat {
+ private RuntimeMXBean rmbean;
+ private MemoryMXBean mmbean;
+ private List<MemoryPoolMXBean> pools;
+ private List<GarbageCollectorMXBean> gcmbeans;
+
+ /**
+ * Constructs a PrintGCStat object to monitor a remote JVM.
+ */
+ public PrintGCStat(MBeanServerConnection server) throws IOException {
+ // Create the platform mxbean proxies
+ this.rmbean = newPlatformMXBeanProxy(server,
+ RUNTIME_MXBEAN_NAME,
+ RuntimeMXBean.class);
+ this.mmbean = newPlatformMXBeanProxy(server,
+ MEMORY_MXBEAN_NAME,
+ MemoryMXBean.class);
+ ObjectName poolName = null;
+ ObjectName gcName = null;
+ try {
+ poolName = new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE+",*");
+ gcName = new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE+",*");
+ } catch (MalformedObjectNameException e) {
+ // should not reach here
+ assert(false);
+ }
+
+ Set mbeans = server.queryNames(poolName, null);
+ if (mbeans != null) {
+ pools = new ArrayList<MemoryPoolMXBean>();
+ Iterator iterator = mbeans.iterator();
+ while (iterator.hasNext()) {
+ ObjectName objName = (ObjectName) iterator.next();
+ MemoryPoolMXBean p =
+ newPlatformMXBeanProxy(server,
+ objName.getCanonicalName(),
+ MemoryPoolMXBean.class);
+ pools.add(p);
+ }
+ }
+
+ mbeans = server.queryNames(gcName, null);
+ if (mbeans != null) {
+ gcmbeans = new ArrayList<GarbageCollectorMXBean>();
+ Iterator iterator = mbeans.iterator();
+ while (iterator.hasNext()) {
+ ObjectName objName = (ObjectName) iterator.next();
+ GarbageCollectorMXBean gc =
+ newPlatformMXBeanProxy(server,
+ objName.getCanonicalName(),
+ GarbageCollectorMXBean.class);
+ gcmbeans.add(gc);
+ }
+ }
+ }
+
+ /**
+ * Constructs a PrintGCStat object to monitor the local JVM.
+ */
+ public PrintGCStat() {
+ // Obtain the platform mxbean instances for the running JVM.
+ this.rmbean = getRuntimeMXBean();
+ this.mmbean = getMemoryMXBean();
+ this.pools = getMemoryPoolMXBeans();
+ this.gcmbeans = getGarbageCollectorMXBeans();
+ }
+
+ /**
+ * Prints the verbose GC log to System.out to list the memory usage
+ * of all memory pools as well as the GC statistics.
+ */
+ public void printVerboseGc() {
+ System.out.print("Uptime: " + formatMillis(rmbean.getUptime()));
+ for (GarbageCollectorMXBean gc : gcmbeans) {
+ System.out.print(" [" + gc.getName() + ": ");
+ System.out.print("Count=" + gc.getCollectionCount());
+ System.out.print(" GCTime=" + formatMillis(gc.getCollectionTime()));
+ System.out.print("]");
+ }
+ System.out.println();
+ for (MemoryPoolMXBean p : pools) {
+ System.out.print(" [" + p.getName() + ":");
+ MemoryUsage u = p.getUsage();
+ System.out.print(" Used=" + formatBytes(u.getUsed()));
+ System.out.print(" Committed=" + formatBytes(u.getCommitted()));
+ System.out.println("]");
+ }
+ }
+
+ private String formatMillis(long ms) {
+ return String.format("%.4fsec", ms / (double) 1000);
+ }
+ private String formatBytes(long bytes) {
+ long kb = bytes;
+ if (bytes > 0) {
+ kb = bytes / 1024;
+ }
+ return kb + "K";
+ }
+}
diff --git a/src/share/demo/management/VerboseGC/README.txt b/src/share/demo/management/VerboseGC/README.txt
new file mode 100644
index 0000000000..f7a9011e42
--- /dev/null
+++ b/src/share/demo/management/VerboseGC/README.txt
@@ -0,0 +1,31 @@
+VerboseGC demonstrates the use of the java.lang.management API to
+print the garbage collection statistics and memory usage remotely
+by connecting to a JMX agent with a JMX service URL:
+ service:jmx:rmi:///jndi/rmi://<hostName>:<portNum>/jmxrmi
+where <hostName> is the hostname and <portNum> is the port number
+to which the JMX agent will be connected.
+
+To run the VerboseGC demo
+
+(1) Start the application with the JMX agent - here's an example of
+ how the Java2D is started
+
+ java -Dcom.sun.management.jmxremote.port=1090
+ -Dcom.sun.management.jmxremote.ssl=false
+ -Dcom.sun.management.jmxremote.authenticate=false
+ -jar <JDK_HOME>/demo/jfc/Java2D/Java2Demo.jar
+
+ This instruction uses the Sun's built-in support to enable a JMX agent.
+ You can programmatically start a JMX agent with the RMI connector
+ using javax.management.remote API. See the javadoc and examples for
+ javax.management.remote API for details.
+
+(2) Run VerboseGC
+
+ java -jar <JDK_HOME>/demo/management/VerboseGC/VerboseGC.jar localhost:1090
+
+These instructions assume that this installation's version of the java
+command is in your path. If it isn't, then you should either
+specify the complete path to the java command or update your
+PATH environment variable as described in the installation
+instructions for the Java(TM) SDK.
diff --git a/src/share/demo/management/VerboseGC/VerboseGC.java b/src/share/demo/management/VerboseGC/VerboseGC.java
new file mode 100644
index 0000000000..bb8e06f08e
--- /dev/null
+++ b/src/share/demo/management/VerboseGC/VerboseGC.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of Sun Microsystems nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ */
+
+import javax.management.*;
+import javax.management.remote.*;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+/**
+ * This VerboseGC class demonstrates the capability to get
+ * the garbage collection statistics and memory usage remotely.
+ */
+public class VerboseGC {
+ private MBeanServerConnection server;
+ private JMXConnector jmxc;
+ public VerboseGC(String hostname, int port) {
+ System.out.println("Connecting to " + hostname + ":" + port);
+
+ // Create an RMI connector client and connect it to
+ // the RMI connector server
+ String urlPath = "/jndi/rmi://" + hostname + ":" + port + "/jmxrmi";
+ connect(urlPath);
+ }
+
+ public void dump(long interval, long samples) {
+ try {
+ PrintGCStat pstat = new PrintGCStat(server);
+ for (int i = 0; i < samples; i++) {
+ pstat.printVerboseGc();
+ try {
+ Thread.sleep(interval);
+ } catch (InterruptedException e) {
+ System.exit(1);
+ }
+ }
+ } catch (IOException e) {
+ System.err.println("\nCommunication error: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Connect to a JMX agent of a given URL.
+ */
+ private void connect(String urlPath) {
+ try {
+ JMXServiceURL url = new JMXServiceURL("rmi", "", 0, urlPath);
+ this.jmxc = JMXConnectorFactory.connect(url);
+ this.server = jmxc.getMBeanServerConnection();
+ } catch (MalformedURLException e) {
+ // should not reach here
+ } catch (IOException e) {
+ System.err.println("\nCommunication error: " + e.getMessage());
+ System.exit(1);
+ }
+ }
+
+ public static void main(String[] args) {
+ if (args.length < 1) {
+ usage();
+ }
+
+ String hostname = "";
+ int port = -1;
+ long interval = 5000; // default is 5 second interval
+ long mins = 5;
+ for (int argIndex = 0; argIndex < args.length; argIndex++) {
+ String arg = args[argIndex];
+ if (args[argIndex].startsWith("-")) {
+ if (arg.equals("-h") ||
+ arg.equals("-help") ||
+ arg.equals("-?")) {
+ usage();
+ } else if (arg.startsWith("-interval=")) {
+ try {
+ interval = Integer.parseInt(arg.substring(10)) * 1000;
+ } catch (NumberFormatException ex) {
+ usage();
+ }
+ } else if (arg.startsWith("-duration=")) {
+ try {
+ mins = Integer.parseInt(arg.substring(10));
+ } catch (NumberFormatException ex) {
+ usage();
+ }
+ } else {
+ // Unknown switch
+ System.err.println("Unrecognized option: " + arg);
+ usage();
+ }
+ } else {
+ String[] arg2 = arg.split(":");
+ if (arg2.length != 2) {
+ usage();
+ }
+ hostname = arg2[0];
+ try {
+ port = Integer.parseInt(arg2[1]);
+ } catch (NumberFormatException x) {
+ usage();
+ }
+ if (port < 0) {
+ usage();
+ }
+ }
+ }
+
+ // get full thread dump and perform deadlock detection
+ VerboseGC vgc = new VerboseGC(hostname, port);
+ long samples = (mins * 60 * 1000) / interval;
+ vgc.dump(interval, samples);
+
+ }
+
+ private static void usage() {
+ System.out.print("Usage: java VerboseGC <hostname>:<port> ");
+ System.out.println(" [-interval=seconds] [-duration=minutes]");
+ }
+}
diff --git a/src/share/demo/management/index.html b/src/share/demo/management/index.html
new file mode 100644
index 0000000000..f9f3506422
--- /dev/null
+++ b/src/share/demo/management/index.html
@@ -0,0 +1,46 @@
+<html>
+<head> <title>java.lang.management Demonstration Code</title> </head>
+
+
+<h1>java.lang.management Demonstration Code</h1>
+
+<ul>
+
+<li>
+<A HREF="FullThreadDump">FullThreadDump</A>
+<br>
+Shows how to get thread dumps and look for deadlocks.
+</li>
+
+<li>
+<A HREF="VerboseGC">VerboseGC</A>
+<br>
+Shows how you can find out about Garbage Collection in the VM.
+</li>
+
+<li>
+<A HREF="MemoryMonitor">MemoryMonitor</A>
+<br>
+Shows how you can find out the memory usage in the VM.
+</li>
+
+<li>
+<A HREF="JTop">JTop</A>
+<br>
+Shows how you can find out the threads with top CPU usage.
+</li>
+
+
+</ul>
+
+
+
+<h2>Comments and Feedback</h2>
+
+<p>
+Comments regarding java.lang.management API or on any of these
+demonstrations should be sent through
+<A HREF="http://java.sun.com/mail">http://java.sun.com/mail/</A>
+
+
+</html>