FeaturesPluginsDocs & SupportCommunityPartners

NetBeans IDE 4.0 Profiler Tutorial

This article was submitted as part of the Win With NetBeans contest. The author's name will be added at the conclusion of the competition.

The NetBeans Profiler is a powerful tool that provides important information about the runtime behavior of your application. While imposing relatively little overhead, the NetBeans Profiler tracks CPU performance and memory usage. This tutorial will show you how to use the Profiler with NetBeans 4.0 to:

Portions of this tutorial originally appeared in a June, 2004 Java Developer's Journal article about JFluid, the underlying technology used by the NetBeans Profiler. All reprinted material is used by permission of the publisher of Java Developer's Journal.

This tutorial should take approximately one hour to complete.

NetBeans IDE 4.0 Quick Start Guide for Web Applications
Starting with NetBeans 4.0 or Java for the first time? See the NetBeans IDE 4.0 Quick Start Guide for Web Applications. Once you have completed it, you will be ready to build on your knowledge with this tutorial!


Setting Up Your Environment



Installing the Profiler

The NetBeans Profiler is in beta and is available as a separate download. To use this tutorial you must install the most recent version of the NetBeans Profiler. Be sure to follow the NetBeans Profiler Download & Install instructions.

Configuring Tomcat

Profiling a web application requires that the web server be run with the JVM that is included with the NetBeans Profiler. So to use the NetBeans Profiler with the Tomcat server a small change to the Tomcat startup script is necessary in order to set JAVA_HOME correctly. In addition, you must "expand" the JVM provided with the NetBeans Profiler by adding folders to it from a v1.4.2 JDK.

Obtaining the required source files

This tutorial uses a web application based on the HelloWeb project created in the NetBeans IDE 4.0 Quick Start Guide for Web Applications. The modifications for this tutorial include the addition of a servlet that handles the incoming request. It creates a Java bean and then dispatches to the JSP that creates the response. The servlet has been poorly written on purpose in order to highlight features of the NetBeans Profiler.

You get all application files from the ProfilingTutorial.zip file.

  1. In your file system, create a folder for the unzipped application files. From now on, this folder will be referred to as $UNZIPHOME.
  2. Click here to download the ProfilingTutorial.zip file.
  3. Use an application that unzips files to unzip the ProfilingTutorial.zip file to $UNZIPHOME.

    $UNZIPHOME now has web and src folders. The web folder contains the two JSP files and the deployment descriptors. The src folder contains the source files for the servlet and Java bean classes.


Creating a Project



Creating a web project from the provided source files

  1. Choose File > New Project (Ctrl-Shift-N). Under Categories, select Web. Under Projects, select Web Project with Existing Sources. Click Next.
  2. In Location, click Browse to select the web application's document root. The document root is $UNZIPHOME, the folder to which you unzipped the ProfilingTutorial.zip file.
  3. In Project Name, type ProfilingTutorial. Click Next.
  4. Click Finish. The IDE creates the $UNZIPHOME/nbproject project folder and the $UNZIPHOME/build.xml file. The ProfilingTutorial project opens in the IDE. You can view its logical structure in the Projects window and its file structure in the Files window.
  5. This final step is only required when using NetBeans with JDK v5. Right Click the ProfilingTutorial entry in the Projects window and choose Properties. In the left pane under Build choose Compiling Sources. In Additional Compiler Options type -source 1.4 -target 1.4 and then click OK.

Running the Project

  1. Make note of the process ID values for all Java virtual machines that are running. This step is necessary because later you will need to know the process ID of the JVM that gets started to run Tomcat. On Unix based systems you can find out the process IDs by entering ps -eaf | grep java at a command prompt:
    $ ps -eaf | grep java
    gs  8132  8104  0 12:49:32 pts/4    0:51 /export/home/gs/tools/java/jdk50_01/bin/java -Djdk.home=/export/home/gs/tools/j
    gs  8104  8101  0 12:49:31 pts/4    0:00 /bin/sh ./../platform4/lib/nbexec --jdkhome /export/home/gs/tools/java/jdk50_01
    gs  8215  8093  0 12:50:59 pts/4    0:00 grep java
    

    On Windows systems you can find out the process IDs by starting the Windows Task Manager application and displaying the Processes in Image Name order. Note that on some versions of Windows the Task Manager does not display the process ID column (PID) by default; choose View > Select Columns and click PID to select the process ID column. The illustration below shows that only one instance of java.exe is currently running, with a process ID of 2848. View Windows Task Manager

  2. In the Projects window right-click the ProfilingTutorial entry and choose Run Project. This will cause the IDE to build the project, start Tomcat, and then display the index.jsp page in a browser window.
  3. Verify that Tomcat started correctly by clicking the Bundled Tomcat tab in the IDE's Output pane. Scroll to the top of the Tomcat output to verify that Tomcat was started with the NetBeans Profiler JVM. Examine the line that begins with Using JAVA_HOME; the Java home should be the folder that contains the NetBeans Profiler JVM. If Tomcat does not start or the JAVA_HOME is not the directory that contains the NetBeans Profiler JVM, then verify that you followed the instructions in the Configuring Tomcat step. Sample output for Windows is illustrated below. View Tomcat output
  4. A browser window should have opened and displayed the http://localhost:8084/ProfilingTutorial/ page. Verify that the web application is working by typing NetBeans User into the name field and clicking the OK button. The result should be similar to the illustration below. View Application Output

Monitoring Runtime Behavior



Attaching to a Running Application

Now that you have verified that Tomcat is using the JVM included with the NetBeans Profiler you can attach the IDE's profiling tools to that JVM and monitor its runtime behavior.

  1. Determine the process ID of the JVM that is running Tomcat. The list of processes that are running java.exe should have grown by one since you last listed them in the Running the Project step. The new java.exe process is the one that was added to run Tomcat. Make a note of its process ID.
  2. Choose Profile > Attach Profiler. In Working Directory type the fully qualified name of Tomcat's bin folder. As an example, a typical value on a Windows system would be:
      C:\Program Files\netbeans-4.0\nb4.0\jakarta-tomcat-5.0.28\bin
    And on Unix the value will be something like:
      /export/home/gs/tools/netbeans/40/nb4.0/jakarta-tomcat-5.0.28/bin
  3. Click the Monitor Application button. Make sure that the Enable Threads Monitoring option is not checked.
  4. Click the Attach button. Select Manually enter PID of the application. In PID type in the process ID of the JVM that is running Tomcat. Click the OK button.

Interpreting the Monitor Graphs

The NetBeans Profiler displays three graphs in the output pane, as illustrated below.
View Monitor Graphs

The graph on the left is the easiest to understand. The red shading indicates the allocated size of the JVM heap, updated approximately once per second. The purple overlay indicates the amount of heap space actually in use. In the example above the allocated heap size at the last update was almost 14 megabytes. Of that 14 megabytes a little over 4 megabytes is actually being used to hold Java objects.

The graph on the right is also easy to understand. It merely shows the count of active threads in the JVM, updated approximately once per second.

The graph in the center is the most interesting. It shows two important heap statistics.

  • The blue line is the percentage of execution time spent by the JVM doing garbage collection and is graphed against the y-axis on the right edge of the graph. Time spent by the JVM doing garbage collection is time that is not available for it to run your application. So if the blue line indicates a large percentage you may want to consider tuning the JVM by configuring a larger heap size (refer to the -Xmx parameter documentation) or perhaps switching to a different garbage collection algorithm.
  • The red line is surviving generations and is graphed against the y-axis scale on the left edge of the graph. The count of surviving generations is the number of different ages of all the Java objects on the JVM's heap, where "age" is defined as the number of garbage collections that an object has survived. When the value for surviving generations is low it indicates that most of the objects on the heap have been around about the same amount of time. If, however, the value for surviving generations is increasing at a high rate over time then it indicates your application is allocating new objects while maintaining references to many of the older objects it already allocated. If those older objects are in fact no longer needed then your application is wasting (or "leaking") memory.

Clicking the View Telemetry Graphs Button button will cause the IDE to display larger versions of the three graphs in the main display pane.


Determining CPU Time Used by a Method



Switching to Performance Analysis Mode

The Profiler is attached to the Tomcat JVM, but is only monitoring high level statistics. To find out detailed information about the performance of a specific method (or methods) in the application you will need to modify the Profiler's settings.

  1. Click the View Modify Profiling Button button or choose Profile > Modify Profiling.
  2. Click the Analyze Performance button.
  3. Select the Part of Application radio button. Then click the Select button that is next to the Part of Application radio button.
  4. Click the Add button.
  5. Click the Select button. The Profiler displays the Select Class tree.
  6. Expand the Source Packages entry by clicking its plus sign icon.
  7. Expand the org.me.hello entry.
  8. Expand the RequestHandler.java entry.
  9. Click the RequestHandler entry and then click the OK button.
  10. The methods in the RequestHandler class are now displayed in the Select Methods dialog as illustrated below. Click the processRequest method and then click the OK button. View Select Methods Dialog
  11. Select the processRequest method by clicking on it in the list of Root Methods and then click the OK button. You have just selected processRequest as the root method for performance analysis. This means that the processRequest method and all methods that it calls, and all methods that they in turn call (and so on) will be monitored. Starting from processRequest, the Profiler does analysis of the method call graph to determine which methods need profiling. Only those methods are profiled - the rest of your application will continue to run at full speed with no profiling overhead.
  12. Click the OK button on the Modify Profiling dialog.

Running the Profiled Method

Now that you have chosen processRequest as a root method you need to use the portion of the web application that causes that root method to run. This is easy to do because the processRequest method handles all requests from the index.jsp page.

  1. In your web browser click the Back button to return to the http://localhost:8084/ProfilingTutorial/ page.
  2. Click the OK button to resubmit "NetBeans User" as your user name. It will take a bit longer before the response appears because the Profiler is monitoring performance of the processRequest method.
  3. After Hello, NetBeans User! displays in your browser, click the View CurrentResults Button button or choose Profile > Get Current Results.

Interpreting the Performance Analysis Graphs

The Profiler displays the latest performance results, as illustrated below.

View Performance Results.

The top window shows the complete method call graph beginning with the root method. The processRequest method ran for 168 milliseconds (ms). Note, however, that very little time was spent running the instructions of the processRequest method itself - the sixth line in the window shows the "self time" for processRequest to be only 0.421 ms. The vast majority of the time was spent in methods called by processRequest. In particular, the forward method took up 84.7% of the execution time. This is not surprising given the amount of work the forward method has been given to do.

The power of the NetBeans Profiler is it helps you identify bottlenecks in your code that were not expected or that will prevent your application from scaling well. Note that the createUniqueID method took up 11.3% of the execution time. You can click the plus sign next to the createUniqueID entry to investigate exactly where the time went. If you examine the source code for createUniqueID you will discover it uses a hideously inefficient algorithm that should be redesigned.

The bottom window is a flatter depiction - it shows the "self time" for each method in the call graph.


Monitoring the Creation of Objects



Switching to Memory Analysis Mode

The Profiler can do detailed analysis (also referred to as instrumentation) of CPU performance or memory usage, but it cannot do both at the same time. To find out detailed information about the allocation and garbage collection of objects on the JVM's heap you will need to modify the Profiler's settings.

  1. Click the View Modify Profiling Button button or choose Profile > Modify Profiling.
  2. Click the Analyze Memory Usage button.
  3. Select the Record both object creation and garbage collection radio button.
  4. Click the OK button.

Running the Profiled Application

Now that you have chosen analyze memory usage you need to use the web application in order to determine whether it is using memory efficiently.

  1. In your web browser click the Back button to return to the http://localhost:8084/ProfilingTutorial/ page.
  2. Click the OK button to resubmit "NetBeans User" as your user name.
  3. After Hello, NetBeans User! displays in your browser, click the browser's Back button to return to the previous page.
  4. Repeat steps 2 through 3 nine times. Repeated submission of the same user name is necessary for this demonstration.
  5. Click the View CurrentResults Button button or choose Profile > Get Current Results.
  6. The Profiler displays the latest memory analysis results in a table. Click the Class Name column to sort the rows by class name.
  7. Scroll down through the table rows until the row for the org.me.hello.NameHandler class is displayed.

Interpreting the Memory Analysis Graphs

The illustration below shows the statistics for the org.me.hello.NameHandler class. View Memory Results.

The columns provide object allocation and memory usage information.

  • Total alloc. obj. (on the far right) is easiest to understand. This is the total count of all objects of this class that have been created. For the NameHandler class this value is 10, which is the number of times you pressed the Ok button on the web application's form.
  • Allocated Objects is the number of objects that the Profiler is actually monitoring. In this example, of the 10 instances of NameHandler that have been created the Profiler is only monitoring 1 of those instances. By default this number will be approximately ten percent of the value of total allocated objects (so the numbers you see might vary a bit from the illustration). By monitoring only a subset of the created objects the Profiler is able to dramatically reduce the overhead it places on the JVM, which then allows your application to run at close to full speed.
  • Live Objects is the number of the Allocated Objects that are still on the JVM's heap and are therefore taking up memory.
  • The two Live Bytes columns show the amount of heap memory being used by the Live Objects. One column displays a graph, the other displays text.
  • The Age Average value is calculated using the Live Objects. The age of each object is the number of garbage collections that it has survived. The sum of the ages divided by the number of Live Objects is the Age Average.
  • The Generations value is calculated using the Live Objects. As with Age Average, the age of an object is the number of garbage collections it has survived. The Generations value is the number of different ages for the Live Objects.

You can use this information to help track down memory leaks. The value for Generations is the same as the Surviving Generations value described in the Interpreting the Monitor Graphs section, but restricted to the objects of a single class. This finer granularity of monitoring can help you find the specific objects that are wasting heap space.

In this example, though, you do not even need Generations to see a problem with the NameHandler class. The Total alloc. obj. value is 10. The intent of the servlet code was to reuse NameHandler objects when the same user name is entered. Clearly, that is not happening. The bug is in the processRequest method: the key used to check for an entry in the Map is not the same as the key used to store the entry. The result is a pretty typical Java memory leak: an object is placed into a Map and then forgotten.

Another handy tool for understanding application behavior is to see where in your code the objects of a particular class are being allocated. This can often provide clues about why an object is still on the heap. The NetBeans Profiler will display stack traces for any class if you right-click the class's entry in the table and choose Show Allocations Stack Traces.

To end the profiling session, choose Profile > Detach.


Exploring Further



Refer to the NetBeans Profiler help file for more information on these topics.

  • When profiling CPU usage a class filter can be defined to prevent the profiling of methods outside your application (for example all methods in java.*). This helps keep your application running at closer to full speed.
  • The Analyze Memory Usage feature can be limited to monitoring just object allocation. This will decrease the Profiler's impact on performance.
  • If when analyzing memory usage you discover that only a few classes seem to be causing problems, you can disable the monitoring of objects of all other classes.
  • Features are available that will monitor your application's startup time or a specific code fragment in your application.
  • Detailed thread statistics are available.

Bookmark this page

del.icio.us furl simpy slashdot technorati digg
Companion
Projects:
MySQL Database Server   Open JDK: an Open SourceJDK   GlassFish Community: an Open Source Application Server    Mobile & Embedded Community    Open Solaris   java.net - The Source for Java Technology Collaboration   Virtual Box - full virtualizer  Open ESB - The Open Enterprise Service Bus Powered by