Paul is a senior software developer at Vonage. He can be contacted at firstname.lastname@example.org.
Java Management Extensions (JMX) technology provides tools for monitoring and managing applications and the resources they use. In this article, I examine how Java 5 carries monitoring and management technology to the next level by instrumenting the Java Virtual Machine itself, thus providing the tools you can use to monitor its functional components.
While MBeans aren't new (see my article "Java Management Extensions," DDJ, July 2004), Java 5 does include a new package called "java.lang.management" that defines nine special MBeans called "platform MBeans" or "MXBeans." Each of these MXBeans (see Table 1) encapsulates a single functional area of the VM. Like all MBeans, each MXBean has a unique javax.management.ObjectName. For MXBeans, the name takes the form java.lang:type=ttt where ttt is a string formed by dropping the trailing "MXBean" from the interface name in column 1 of Table 1.
MBeans are not accessed directly by an application. They reside inand are managed bya repository called an "MBean server," which implements the interface javax.management.MBeanServer. Java 5 features a special MBean server called the "platform MBean server," which is built into the VM. Platform MBeans are registered in this server using their unique names.
You access the platform MBean server by invoking the static getPlatformMBeanServer method of the java.lang.management.ManagementFactory class. Examine ListMBeans (available at www.ddj.com/code/ddj.html) and you see this code:
MBeanServer mbs =
which obtains a reference to the platform MBean server.
The displaySortedBeanList() method in ListMBeans uses the MBeanServer's queryNames() method to get the names of the MBeans controlled by the server. It sorts the list and displays it. If you examine the output from the program (Figure 1), you can see that the list includes each of the MXBeans in Table 1. You probably also noticed that Figure 1 displays a list of 18 MBeans followed by a second list of 19 MBeans. The additional MBean in the second list, which has the unique identifier ca.tremblett.ddj:name=My MBean, is an instance of MyMBean (available at http://www.ddj.com/code/ddj.html). To see where it was registered in the MBean server, examine the registerMBean() method of ListMBeans. The fact that ListMBeans can register an MBean demonstrates that the MBeans managed by the platform MBean server are not limited to those that are registered by the VM. Furthermore, because there is usually no need for more than a single MBean server, I suggest you use the platform MBean server unless you have a good reason to create your own using the MBeanServerFactory class.
If you examine the javadocs for the interfaces in Table 1, you find more than 50 getter methods. You can use the information returned by these methods to make a detailed assessment of the state of the virtual machine at any point during the execution of your application. The program MXBDemo1 (available electronically) shows how to use some of the getter methods. Notice that the platform MBeans are obtained using static methods of the ManagementFactory class. Figure 2 is output from the program.
In addition to the getter methods, some of the management interfaces define setter methods that you can use to control the behavior of the VM. Say your application is using Class.forName(someClassName).newInstance() and you are encountering what you suspect might be a problem related to the class loader. You could run the program using the VM argument -verbose:class, but you would be faced with the task of sorting through a potentially large volume of output. A better approach would be to obtain the ClassLoadingMXBean, invoke its setVerbose(true) method just before you create your instance followed by setVerbose(false) immediately following the code you are attempting to debug. This is demonstrated in MXBDemo2 (available at www.ddj.com/code/ddj.html). When you run this program, it produces the output shown in Figure 3. Notice that verbose output is generated only for the third class that is instantiated.
A Practical Use of Platform Beans
Suppose you are developing an application that will create some number of worker threads and you are faced with the issue of how to set a limit to that number of threads so as not to exhaust all available heap memory. One approach might be to pass the number to the application as a command-line argument or as a property in a properties file. In either case, the number you choose tends to be arbitrary or a best guess. A better approach might be to use runtime data you obtain from platform MBeans to determine the number of threads.
Take a look at MXBDemo3 (available at www.ddj.com/code/ddj.html). It starts by scheduling a TimerTask that displays garbage collection statistics and memory usage every 30 seconds. It then enters a while loop that creates and starts threads for a maximum of 30 seconds. Before it creates a thread, however, the program determines the amount of available heap memory. If the heap is more than 50 percent utilized, it defers creating the thread. After the maximum possible number of threads have been started, the program waits until all threads have completed, and then exits. To minimize the number of threads that the program creates and the volume of output it produces before it completes, the VM arguments -Xms1m and -Xmx2m (1-MB initial heap size, 2-MB maximum heap size) are specified.
Admittedly, the example is contrived and its simple logic would prove inadequate for real-world use; however, it should suffice to demonstrate how you can use platform MBeans.
Each generation of the Java platform delivers new functionality that results in the development of better applications. The introduction of platform MBeans and the platform MBean server in Java 5 is proof.