Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Identifying memory leaks with the WebSphere Studio Profiler and the JDK Heapdump utility

Jiwu Tao (jiwu2@us.ibm.com), Software Engineer, IBM Software Services for WebSphere for IBM
Jiwu Tao is a software engineer working at IBM WebSphere Competency Center, Pittsburgh, PA. He is a certified System Expert on WebSphere Application Server. Prior to this, he worked with WebSphere Application Server development team and was a key developer in WebSphere Application Server EJB caching research project. He holds two Master degrees in Information Science and Electrical Engineering. Before joining IBM, He taught in universities and published several articles in the field of computer science. You can reach Jiwu at jiwu2@us.ibm.com
Priamo Persichetti (priamop@us.ibm.com), Software Engineer, IBM Software Services for WebSphere for IBM
Priamo Persichetti works in the WebSphere Competency Center, Pittsburgh Lab, Pittsburgh, PA. He is a Certified System Administrator/Expert for WebSphere Application Server V5.0 and 4.0. Prior to his current position, he worked on IBM's electronic software distribution tool (ISSI) as part of the packaging team and IBM's Edge Server product. He has a Master's degree in Information Science. You can reach Priamo at priamop@us.ibm.com

Summary:  Java's automatic garbage collection makes it much easier to manage memory use in Java and J2EE applications, but it does not help manage references to objects. If object references are not removed when necessary, memory leaks can occur and cause critical performance problems. This article explains how the WebSphere Studio Profiler can help you solve memory leak problems, and how the IBM Heapdump and HeapRoots tools can help with problems that may be too complex for the WebSphere Studio Profiler. For each tool, the article describes the performance considerations and suitability for special tasks, then uses sample code to show you how to efficiently use the tools to debug Java memory leak problems in J2EE applications.

Date:  09 Nov 2004
Level:  Introductory

Activity:  12396 views
Comments:  

Introduction

Profiling memory use and debugging memory leaks in application code in the early stages of development is considered a best practice for application development. It can provide early detection of memory problems long before the production stage. Taking the time to profile and debug memory usage issues during proof-of-concept or development milestones will avert major architectural changes late in the application life cycle.

Before introducing the IBM® memory profiling and debugging tools, let us have a quick look at the issue itself -- memory management and memory leaks in Java™ and J2EE applications.

Garbage collection and memory management in Java applications

As a modern language, Java has an automatic memory management mechanism called garbage collection, which makes it much easier for you to manage objects created in the application code. When an object is created by new keyword, it is placed into the Java heap of the Java Virtual Machine (JVM). The JVM has a garbage collector, and when this object is no longer needed by any code, the garbage collector removes it from the Java heap. Listing 1 is an example of a method defined in a Java class:


Listing 1. Example method in Java class
 

public void aMethod() { 
    String s = new String("My string"); // String is a Java class
} 

In this example, a new String object is allocated in the Java heap. Unlike coding in C or C++, you don't need to write code to explicitly delete the object from the heap after you're done with it. When the method is called and returned, the only reference to this String object, s, is set to null and removed from the thread stack. The JVM garbage collector detects that the number of references to this String object is 0, indicating no code may access or use the object any longer. When the garbage collector has an opportunity to run, it treats this String object as garbage, removes it from the Java heap, and frees the memory allocated for it.

Memory leaks in Java

The garbage collector frees you from manually releasing the memory used by the objects after you are finished with them. Garbage collection makes code much safer, because explicitly deleting objects from memory is error-prone. However, garbage collection is not a panacea. If you don't manage the references to the Java objects carefully, they may face another type of memory leak problem. In the above example, if s, the reference to the String object, is not a local variable, but a instance variable or even a class variable (which exists for the life of the application), this reference may be valid throughout the life of the running application. The String object will never be removed from the Java heap. This may be a desired effect, but if not, it's a memory leak.

Java application vs. J2EE application

J2EE applications are component-based multi-tier enterprise applications running inside an application server. From the perspective of the JVM, the combination of the application server and its J2EE applications comprise a single large Java application. The tools introduced in this article are the ones to profile or debug memory issues in Java applications, not issues specific to J2EE applications. Thus, the terms Java application and J2EE application are interchangeable in many cases. But bear in mind that J2EE applications are large-scale enterprise applications that may run continuously on a server for many days or months. A memory leak that can be ignored in a typical Java application may cause a severe memory shortage or an application crash in a J2EE application.

Java heap vs. system heap

When the IBM JVM is launched as an operating system process, it allocates two heaps for itself from the system memory. The first one is called the Java heap and contains the Java objects created by the system and Java applications. In the J2EE environment, it also holds the Java objects created by IBM WebSphere® Application Server (hereafter called Application Server). The second heap is called the system heap. It stores the objects that usually have a life expectancy of the life of the JVM, such as class objects and Java Native Interface (JNI) objects. Given that J2EE applications usually do not cause memory leaks in the system heap, the rest of this article shows you how to use IBM tools to deal with memory leaks in the Java heap.


Finding memory leaks

Usually, solving a memory leak problem is a two-step process: identifying which Java classes caused the memory leak, and then determining where in the application the leak occurred. The goal of the first step is easy to achieve with the tools. The second step is more challenging, because tracking the relevant information in a profiling tool slows down performance. The profiler discussed in this article does not provide the detailed information needed to track down the source of memory leaks in the code, partly because of performance considerations. Some tools may be configured to collect such information with significant adverse impact on performance, such as Hprof and other third party tools. Given the scale of J2EE applications and the J2EE environment associated with them, performance concerns often prevent developers from tracking sufficient information using those tools.

To simplify the discussion of resolving the difficulty in the second step in this article, memory leaks are divided into two types.

Rarely used object leak
A memory leak in which the leaked Java object belongs to an infrequently used Java class. In a J2EE environment, a JVM often holds millions of objects, some created by Application Server and others are created by applications running inside Application Server. Typically, the objects of an application-defined Java class are only created and referred to in a limited number of places in the application. The leaks of these objects often belong to this type. In this scenario, the second step of identifying the leak is straightforward. Because the objects that belong to the same class of the leaked object are only used in a few places, you can easily locate the source of the memory leak by checking the application code where these objects are used.
Frequently used object leak
A memory leak in which the leaked object belongs to a widely used Java class. Many Java classes in standard java and javax packages, as well as in utility Java classes defined in applications, are frequently used classes, such as java.lang.String. In this scenario, the second step of the process can be difficult. Without sufficient information, it's hard to locate the code causing this type of leak, because objects of the same type are defined in numerous places in applications, and even in WebSphere Application Server. Checking all the places where these objects are used is far too time-consuming.

To resolve the difficulty of the frequently used object leak, obtaining the object reference chain that contains the leaked objects is very helpful. With this information, and some familiarity with the application, you can often find the memory leak code with little effort. For example, object A has a reference to object B, object B has a reference to object C, and object C is the leaked object. Object A, B, and C form an object reference chain, denoted by A=>B=>C. If this chain is long enough, or if any object in this chain is a rarely-used object, the chain is quite distinctive. It can then be mapped to the source code to identify which object C is actually the leaked object. The IBM JDK and its support team have provided the tools to obtain this information with minimal performance impact. By analyzing these reference chains, you can find which chain is relevant to the memory leak and use this chain to locate the source code where the leaked objects are allocated. For a step-by-step example, see Heapdump and HeapRoots.


Overview of profiling and debugging tools

As the premier integrated development environment for J2EE applications, Application Developer provides a Profiler tool to diagnose memory leak problems in J2EE applications. Also, the IBM JDK utility Heapdump, and a standalone heapdump analysis tool called HeapRoots, are more powerful tools for debugging memory leaks. The Profiler is fully integrated with Application Developer and is ideal for identifying rarely used object leaks in Application Developer. For frequently used object leaks, the information provided by the Profiler may not be enough, and you will need to use Heapdump and HeapRoots to find the memory leak.

The IBM JDK also has a utility called Hprof. Like the Application Developer Profiler, Hprof uses the Sun Java Virtual Machine Profiling Interface (JVM PI) to collect the profiling information from the running JVM. It can provide detailed stack trace information about the memory allocation in each thread. This article will not describe this tool because Heapdump and HeapRoots are better choices for J2EE developers. For more information on Hprof, see IBM JVM Diagnostics Guide.

To monitor garbage collection activities, turn on JVM verbose garbage collection (verbosegc), which often gives you a good idea whether there is a memory shortage in the Java heap. To learn more about how to turn on the verrbosegc option for the Application Server process in the WebSphere Administrative Console, see Web module or application server dies or hangs in Application Server InfoCenter and search on "garbage collection."

The following table compares these tools.


Table 1. Comparison of profiling and debugging tools
ToolsDescriptionAdvantages and suitabilityDisadvantages
ProfilerApplication Developer Profiling tool for inspecting the performance of applications
  • Fully integrated with Application Developer
  • Easy to understand and use
  • Good for debugging Rarely-used Object Leak problems
  • Moderate performance impact
  • Not lending itself to resolving frequently used object leak problems
  • Less reliable than Heapdump
Heapdump/HeapRootsJDK Utility for generating heapdump/Standalone heapdump analysis tool
  • Little performance impact
  • Very reliable
  • Best for solving both Rarely-used and frequently used object leak problems in large scale applications
  • Not integrated with Application Developer
  • Configuration required
  • Learning required to use HeapRoots
HprofJDK Profiling tool for inspecting the performance of applications
  • Able to pinpoint the location of memory leaks in the code
  • Relatively easy to understand and use
  • Good for solving both Rarely-used and frequently used object leak problems in small scale applications
  • Not integrated with Application Developer
  • Configuration required
  • Considerable performance impact
  • Less reliable than Heapdump

This article uses Application Developer V5.1.2, its embedded copy of WebSphere Application Server V5.1 (also called the WebSphere Test Environment or WTE) and HeapRoots HR205.jar on Windows 2000 to demonstrate how to use these tools to debug memory leaks in J2EE applications.


Application Developer Profiler

The Profiler provided by Application Developer is a tool to inspect the performance of Java applications. The application profiling is made possible by using the standard JVMPI interface. A JVMPI implementation (known as the agent) runs as part of a standard JVM. The agent receives and records information from the JVM, such as memory allocation and thread activities. The agent may also request additional information or deactivate further notifications of specific events by configuring the Filter feature in the Application Developer Profiler. The Profiler uses the IBM Agent Controller to communicate with JVMPI agents and collect the performance information. You can use the Profiler on local or remote Java processes and even on distributed applications. Processes can be launched for immediate profiling or the profiling can attach to an existing process.

This article focuses on how to identify and isolate memory issues by using the memory usage information collected by Application Developer Profiler..

The Profiler's views

The Profiler has several views to show profiling data. Three of them are relevant to our discussion: Class Statistics view, Package Statistics view, and Instance Package Statistics view. Using any of them, you can solve rarely used object leak problems. You can easily identify the leaked object based on the number of object instances or the total size of these object instances. Since the leaked object is used only in several places in the application, its location can be identified based on its class and package name. However, if the leak is caused by frequently used Java classes such as java.lang.String, you need to obtain additional information by collecting and analyzing the heapdump with the IBM JDK tools discussed below.

Sample application for rarely used object leak

The two sample applications used in this article are packaged in memLeakApp.ear, which you can download below. Listing 2 shows the sample code of the first application:


Listing 2 Rarely-used Object Leak sample code
 
public class MemLeakServlet extends HttpServlet implements Servlet {
    MemLeakClass[][] leakArray;
        public void init() throws ServletException {
            super.init();
            leakArray = new MemLeakClass[1000][1000];
        }	
        public void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
            for (int i = 0; i<1000; i++)
            for (int j= 0; j<1000; j++)
                leakArray [i][j] = new MemLeakClass();
                try
                    { resp.getWriter().println(" The MemLeakServlet has been invoked."); }		
                catch(Exception e)
                    { System.out.println(e.toString()); }
        }
}

public class MemLeakClass {
    public String leakString;
    public MemLeakClass() {
    leakString = new String("abcdefghijklmnopqrstuvwsxyz abcdefghijklmnopqrstuvwsxyz " + 
     "abcdefghijklmnopqrstuvwsxyz abcdefghijklmnopqrstuvwsxyz abcdefghijklmnopqrstuvwsxyz");
    }
}

In this example, two classes are defined to simulate a rarely used object leak. The first class is a servlet called MemLeakServlet. The second class is a simple Java class called MemLeakClass, which is the class of the leaked object. Because class MemLeakClass has a String variable, the String is a leaked object as well. MemLeakServlet has an instance variable called leakArray. It is a 1000 * 1000 two-dimensional array that contains a million MemLeakClass object instances. Application Server's Web Container only loads one servlet instance for each servlet during the lifetime of the application. Therefore the array leakArray will not be garbage collected unless the application is stopped and the servlet is unloaded by the Application Server runtime. This situation introduces a memory leak because the one million MemLeakClass objects are referenced by leakArray and are kept in the Java heap for the lifetime of the application.

Software prerequisites

The Profiler requires the correct version of the IBM Agent Controller to be installed. The Agent Controller is shipped with Application Developer and you can install it using launchpad.exe, the Launch Pad of its installation image.

Steps for profiling the sample application

To profile this sample application in Application Developer:

  1. Go to Windows Service panel and make sure the IBM Agent Controller is started as a service.
  2. Import the sample application into Application Developer.
  3. Configure a server in the Server perspective and add the application into the server.
  4. Start the server in profiling mode: right-click the server and select Profile in the pop-up menu.
  5. Configure the Profiler (see next section for more details).
  6. Start the Profiler monitor in the Profiling and Logging perspective.
  7. Run the sample application.

For details on using the Profiler, see J2EE Application Profiling in WebSphere Studio, or the Help menu (Information Center) of Application Developer. The following sections describe how to configure the Profiler and run the sample application:

Configuring the profiler

When the server is starting in profiling mode, a profiling wizard is automatically invoked. Use the wizard to configure the Profiler. Usually, the default WebSphere J2EE filter set is the best choice to start with. In this example, the most valuable information needed to identify the leak is the total number of object instances of MemLeakClass and String. But the default filter sets will filter out all the classes in package java.*, including String. To avoid this, you must configure a new filter set in this wizard. The major steps of the Profiler configuration are described below and the selected options are indicated in the following figures.

  1. From the Agent page, select the agent for the application server process (such as Unknown[PID:2252]) in the Agents panel and move it to Selected agents panel on the right side.
  2. Click Next twice and skip to the Profiling Filters page.
  3. In the Profiling Filters page, click Add on the right side of the Select a filter set panel and add a new filter set called memLeak (See Figure 1). Select this new filter set. The contents of panel are updated to reflect the filters defined in this filter set:
    Figure 1. Creating a new filter set
    Figure 1 window. Creating a new filter set
  4. To add a new filter in the just created filter set, click Add on the right side of Contents of selected filter set panel. Then specify the package name and the rule for the new filter in the Add filter pop-up (see Figure 2). In this example, the package name is java.lang.* and the rule is INCLUDE. Figure 3 shows the Profiling Filter page when these steps are done. Click Next to go to the next page.
    Figure 2. Adding a new filter
    Figure 2 window. Adding a new filter

    Figure 3. Created a new filter in the new filter set
    Figure 3 window. Created a new filter in the new filter set
  5. Keep the default settings for Profiling Option page and click Finish to close the wizard.

Now, the Profiling and Logging perspective is opened in Application Developer. Select the first profiler (Java Profiling Agent) of the server process in the Profiling Monitor view and click Start Monitor to start the profiler. By default, there are two profilers for each process:

  • Java Profiling Agent
  • J2EE Request Profiler

Java Profiling Agent is listed as Profiling in Profiling Monitor View. This is what you will use to profile the application. J2EE Request Profiler is not used here.

Profiling the sample application

After configuring and starting the Profiler, use the following steps to profile the application server process in which the sample application runs:

  1. Open a Web browser inside (or outside) of Application Developer.
  2. In our example, a JSP is used to invoke the servlet MemLeakServlet. The URL for the JSP on the local machine is http://localhost:9080/memLeakWeb/welcome.jsp. Click Invoke servlet in the JSP to run the servlet.
  3. After the servlet returns the message The MemLeakServlet has been invoked, go to the Profiling and Logging perspective, select Java Profiling Agent of the server process, and check either of the two views: Class Statistics view or Package Statistics view.

The views mentioned in Step 3 show that there are a huge number of String and MemLeakClass object instances, which indicates that they are the leaked objects. Even if you run garbage collection manually from the Profiler Monitor view, these MemLeakClass and String object instances are still in the memory. MemLeakClass is a rarely used Java class, which means the locations of this type of objects in the application code can be easily identified. By checking the code of MemLeakClass, it is also obvious why there is a leak for the String object as well: each MemLeakClass object has a String instance variable pointing to a String object. Thus, the information provided by the Profiler is enough to solve this kind of memory leak. Figure 4 shows the Class Statistics view in the Profiling and Logging perspective:


Figure 4. The Class Statistics view
Figure 4 screenshot. The Class Statistics view

The above example shows that the Application Developer Profiler is good for identifying rarely used object leaks. As mentioned before, it may not be able to provide enough information for a frequently used object leak. For example, if the Class statistics view shows that only String object is the leaked object, it would be hard to determine where the memory leak is in a reasonably sized J2EE application, because String is a common Java class and it is used in many places throughout applications. Fortunately, that is where Heapdump and HeapRoots come to the rescue, as described below.

There is a performance impact when using the Profiler in Application Developer. When Application Server runs in profiling mode, it runs more slowly. On the other hand, the Heapdump tool discussed next causes little performance degradation because the overhead is incurred only when the Heapdump is actually performed.


Heapdump and HeapRoots

Heapdump and HeapRoots are powerful tools for debugging memory problems. They are commonly used by IBM product support teams to analyze memory issues in the WebSphere environment, and they provide the useful information needed to diagnose most Java memory leaks.

Heapdump is a utility shipped with the IBM JDK. It lets you dump all the living objects in the Java heap into a text file, called heapdump.

The heapdump generated by the Heapdump utility is huge and difficult to read. It contains millions of items recording the objects stored in the Java heap. HeapRoots is a much-needed tool to analyze the heapdump and provide the information to investigate memory issues. For instance, HeapRoots can provide a list of objects sorted by size, or by total size of the subtree of the objects. The subtree of an object may contain all the objects to which this object refers, directly or indirectly, including itself.

HeapRoots can also traverse the heap, organize the objects into a tree structure based on their reference relationship, and write them to the output as indented trees. The roots of the trees are the root objects in the Java Heap. The HeapRoots output may filter out the small objects based on a threshold of the total size of the object's subtree. Most of the time, the objects' property, the total size of the subtree, can help you discover the leaked object. For example, in the first sample application, MemLeakServlet is the object that has references to the leaked MemLeakClass objects. Each MemLeakClass has a reference to a String object. Hence, MemLeakServlet's subtree contains all the MemLeakClass objects and the String objects referred to by those MemLeakClass objects. Therefore, the total size of MemLeakServlet's subtree is very large because it is greater than the sum of the sizes of those MemLeakClass and String objects.

By identifying the root objects with a large subtree size in the HeapRoots output and scanning the objects in these subtrees, you can easily chase down MemLeakServlet from a root object along the reference chains and find that this servlet contains a large number of MemLeakClass objects, which is the indicator of a memory leak in this class. Based on the objects in this object reference chain, the location of the memory leak in the source code can be identified as well. Hence, Heapdump and HeapRoots provide the critical information needed to solve a memory leak problem, even for the case of frequently used object leak, as mentioned in the section Finding Memory Leaks.

This article does not cover the all features and functions of HeapRoots. For more information, see the HeapRoots documentation on the HeapRoots Web site. This article shows you how to enable Heapdump and generate a heapdump in the Application Developer environment, using an example to show you how to identify the memory leak using HeapRoots.

Methods to trigger Heapdump

There are several ways to trigger a heap dump in the IBM JVM. In the Application Developer environment, the heapdump is generated automatically when an OutOfMemory error or heap exhaustion situation occurs.

But application developers should not defer debugging the memory leaks until an OutOfMemory error happens. Fortunately, there are two other ways to trigger the Heapdump explicitly. The first one is sending a specific signal to the Application Server JVM process. On the Windows platform, this signal is SIGINT. Typing Ctrl+Break is the common way to send this signal to the process started from a command line window. But in the Application Developer environment, it is not an option because there is no command line window associated with the embedded Application Server process. You would have to find a program that can generate the SIGINT signal to Windows processes, or write such a program by yourself. The second way to trigger the Heapdump is inserting a HeapDump() method within the application code. This is the recommended approach. It is not only simple to use but also provides the option to dump the heap at a specific point in the application.

Prerequisites for explicitly generating a heapdump

To explicitly generate a heapdump, activate the Heapdump utility before starting the JVM process by setting the environment variable IBM_HEAPDUMP to true for the JVM process. For JDK releases later than JDK 1.3.1, SR3, IBM_HEAPDUMP may be set to any value. There are two alternatives to set IBM_HEAPDUMP for the Application Server JVM process in Application Developer:

Specify the environment variable IBM_HEAPDUMP in a command line window and run Application Developer from there:

  1. Open a command line window.
  2. Set the environment variable from the command line: SET IBM_HEAPDUMP=true.
  3. Start Application Developer from the command line window by running EXE file wsappdev.exe. For example, C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1.2\wsappdev.exe.

Set IBM_HEAPDUMP as a Windows system environment variable:

  1. Right click My Computer icon from Desktop.
  2. Select Properties in the pop-up menu.
  3. Select Advanced tab in the pop-up System Properties window.
  4. Click Environment Variables.
  5. Click New in System Variables panel.
  6. In the pop-up window, specify IBM_HEAPDUMP for Variable Name and true for Variable value.
  7. Click OK for all the pop-up windows to save the new environment variable setting.

Tip: Do not specify the environment variable IBM_HEAPDUMP=true in the WebSphere Administrative Console of the WebSphere Test Environment. It will not work because the setting will not be picked up when the server starts. This is not the case in the standalone Application Server environment. If IBM_HEAPDUMP=true is set in WebSphere Administrative Console by selecting Servers => Application Servers => server_name => Process Definition => Environment Entries, then Heapdump will be enabled in the typical Application Server environment.

Sample application for frequently used object leak

Listing 3 shows the sample code to demonstrate the frequently used object leak and how the HeapDump() method is used to generate the heapdump:


Listing 3. frequently used object leak sample code

public class MemLeakServlet2 extends HttpServlet {
    String[][] leakArray;
    public void init() throws ServletException {
        super.init();
        leakArray = new String [1000][1000];
    }	
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
        for (int i = 0; i<1000; i++)
        for (int j= 0; j<1000; j++)
        leakArray [i][j] = new String("abcdefghijklmnopqrstuvwsxyz " + 
            "abcdefghijklmnopqrstuvwsxyz abcdefghijklmnopqrstuvwsxyz " + 
            "abcdefghijklmnopqrstuvwsxyz abcdefghijklmnopqrstuvwsxyz" );
        Dump.HeapDump();
        try
            { resp.getWriter().println("The MemLeakServlet2 has been invoked."); }		
        catch(Exception e)
            { System.out.println(e.toString()); }
    }
}      

This second example simulates a frequently used object leak. It is similar to the first example. The major difference is that the rarely used object MemLeakClass is removed and the only leaked object is String, which means that Application Developer Profiler will show that String is the only leaked object. It can be difficult to find the leak in the source code because String is used in many places in a typical J2EE application. Heapdump and HeapRoots are needed to solve the puzzle. Another difference from the first sample application is that Dump.HeapDump() is added to trigger the Heapdump.

Invoking Heapdump

This second sample application is also in memLeakApp.ear. To run it, start the server in the normal mode in Application Developer and access welcome2.jsp from a Web browser on the local machine: http://localhost:9080/memLeakWeb/welcome2.jsp. Then click Invoke servlet to run the servlet, just like running the first sample application.

After invoking the servlet, the heapdump is generated by the method Dump.HeapDump() . You may find the heapdump file in the current working directory of the Application Server JVM process. For example, if Application Developer is started from the Start menu, the current working directory for the Application Server JVM process is where wsappdev.exe resides. In our test environment, for instance, it is C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1.2\. The name of the heapdump file is formatted as heapdump.date.time.id.txt, such as heapdump.20040831.182458.2332.txt. The console view of the Server perspective in Application Developer shows a message similar to the one below, indicating the name and the location of the heapdump file:

 
JVMDG315: JVM Requesting Heap dump file
...........JVMDG318: Heap dump file written to C:\Program Files\IBM\WebSphere 
Studio\Application Developer\v5.1.2\heapdump.20040831.182458.2332.txt

After the heapdump is generated, use HeapRoots to analyze it and find out which object refers to a large chunk of other objects that can't be released by the JVM garbage collector. Usually, the objects with a large subtree size are the targets of the investigation.

Setting up HeapRoots

Download HeapRoots from the HeapRoots Web site (free registration required). It contains HeapRoots documentation and the HeapRoots JAR file HR205.jar. Unzip the downloaded zip file in a directory such as C:\workspace. To simplify the commands used here, put the generated heapdump file in the same directory.

Using HeapRoots

To invoke HeapRoots and dump the result to a text file:

  1. Change to the directory where HeapRoots JAR file and heapdump file reside: cd C:\workspace
  2. Load the heapdump file with HeapRoots:
     
    C:\Program Files\IBM\WebSphere Studio\Application Developer\v5.1.2\runtimes\base_v51\java\bin\java.exe" 
    -Xms500M -jar HR205.jar heapdump.20040831.182458.2332 
    

    In above command, heapdump.20040831.182458.2332 is the name of the heapdump file. The java.exe is the one shipped with WTE. The JVM option -Xms500M is used to increase the initial heap size of the JVM running HeapRoots to 500 MB. For a very large Heapdump on the order of 1 GB, increase the value of this parameter accordingly.

  3. Run HeapRoots dump command from the HeapRoots prompt to process the heapdump and output the result to a text file:
    d > C:\workspace\heapAnalysis.txt
    In above command, d is the HeapRoots dump command. The output of the dump is redirected to the file C:\workspace\heapAnalysis.txt.

In Figure 5, the command line window shows some of the HeapRoots output when HeapRoots is invoked and the heapdump file is loaded. The output shows the information getting from the heapdump, such as the number of objects and the number of object references recorded in the heapdump. The size of memory used by HeapRoots is listed here as well. It also shows that the HeapRoots dump command is issued from the HeapRoots command prompt.


Figure 5. HeapRoots output and the dump command issued
Figure 5 screenshot. HeapRoots output and the dump command issued

After issuing the dump command, HeapRoots writes more output to the console window and asks you to enter three parameters for the dump command: total-size threshold, max depth, and dump root address. See the following list for the values specified for these parameters.

Total-size threshold
Use default value of 1MB by pressing the Enter key at the prompt, which means that the object is filtered out if the total size of this object's subtree is smaller than 1 MB.
Max depth
Set it to 100 by entering the number 100 and pressing Enter. It tells the HeapRoots dump command that the maximum depth (maximum length of the object reference chain) in the tree is 100.
Dump root address
Use the default value that includes all root objects in the heap. Simply press Enter.

Figure 6 shows the HeapRoots dump command console output and its parameter values specified from the command line window:


Figure 6. HeapRoots dump command output and its parameter values
Figure 6 screenshot. HeapRoots dump command output and its parameter values

Analyzing HeapRoots output

The output of HeapRoots organizes the objects into indented trees. The root of a tree is a root object in the heap. The objects referenced by the root object are the children of the root object. The objects referenced by these children are the grandchildren of the root object, and so on. For detailed information, refer to the HeapRoots documentation.

Using Application Developer Profiler or the HeapRoots command tc (Refer to the HeapRoots document for this command's usage), it is easy to discover that String is the leaked object in this sample application. To determine the location of the memory leak where the String is used, open the output file heapAnalysis.txt with a text editor and search for String. The result is strikingly simple in this case as there is only one String-related item in the file: the String array defined in MemLeakServlet2. Here is the relevant part of the output:

 
<92>            [36,020,424] 0x19abef40 [64] com/ibm/ws/webcontainer/servlet/StrictServletInstance
<93>	         [36,020,328] 0x19abf290 [24] memleak/MemLeakServlet2
<94>                [36,020,304] 0x19ace850 [4,016] array of [Ljava/lang/String
                    - 1000 children of 0x19ace850 filtered.
                    - 1 child of 0x19abf290 filtered.
                    - 6 children of 0x19abef40 filtered.
                    - 7 children of 0x19abefd8 filtered.
                    - 2 children of 0x19ac7a30 filtered.

The data format for each object in the output of HeapRoots dump command is:

 
<depth>        [total size] address [object size] class
               - Information on the children being filtered out.

The depth in angle brackets <> is the depth of the object in the tree. In this example, the depth of the String array is 94, which means the String array is the 94th generation of the root object. That is, the length of the reference chain from the root object to the String array is 94. The total size in the first square brackets [] is the size of the object's subtree in bytes, which includes the size of the objects directly or indirectly referenced by this object. The address is the hexadecimal memory address of the object in the Java heap. The object size is the actual size of the object in bytes. After that, it indicates the Java class of the object. If there are additional lines for this object, they are used to list its children being filtered out.

Based on the above information, you know that the object reference chain pointing to the array of the String is StrictServletInstance => MemLeakServlet2 => array of String, and that the String array has a thousand children, which consume 36 MB of memory. This information tells you that the simulated String object leak occurs in the MemLeakServlet2 object.

Hints on using HeapRoots

There are several issues to be aware of when using HeapRoots.

  1. As of Nov. 2004, the HeapRoots HR205.jar file downloaded from the HeapRoots Web site sometimes throws java.lang.NumberFormatException if the heapdump file is generated by a 1.4.2 JDK. This is a known issue.
  2. The setting of max depth of the HeapRoots output trees should be large enough to reveal the leaked objects being referred to. In our example, it is 100. To solve the memory leak in a typical J2EE application, you may need to set it to a much larger number.
  3. Locate the leaked object based on the total size of the object's subtree. If an object's subtree, but none of its children's subtrees, consumes a large amount of memory, this object is the parent of the leaked object. In the above examples, this parent object is MemLeakServlet or MemLeakServlet2. You can find the leaked object inside this parent object.
  4. Use the JVM option -verbosegc to turn on JVM verbose garbage collection if you suspect there are extensive garbage collection activities. This situation often leads to very large and deep object reference trees in the HeapRoots output, which are more time-consuming and difficult to analyze. Try to avoid this by dumping the Java heap before it occurs.

Conclusion

This article showed you how to identify Java memory leak problems using the IBM tools Application Developer Profiler, JDK Heapdump, and HeapRoots. It illustrated how to approach an application memory leak problem in the Application Developer environment and how to efficiently diagnose the problem with these tools. It then used examples to show you how to set up, configure, and use these tools to solve simple and more complex memory leak problems.


Acknowledgements

The authors would like to thank Vikram Desai and Jiawan Chen of IBM for reviewing this article.



Download

NameSizeDownload method
memLeakApp.zip7 KBFTP|HTTP

Information about download methods


Resources

About the authors

Jiwu Tao is a software engineer working at IBM WebSphere Competency Center, Pittsburgh, PA. He is a certified System Expert on WebSphere Application Server. Prior to this, he worked with WebSphere Application Server development team and was a key developer in WebSphere Application Server EJB caching research project. He holds two Master degrees in Information Science and Electrical Engineering. Before joining IBM, He taught in universities and published several articles in the field of computer science. You can reach Jiwu at jiwu2@us.ibm.com

Priamo Persichetti works in the WebSphere Competency Center, Pittsburgh Lab, Pittsburgh, PA. He is a Certified System Administrator/Expert for WebSphere Application Server V5.0 and 4.0. Prior to his current position, he worked on IBM's electronic software distribution tool (ISSI) as part of the packaging team and IBM's Edge Server product. He has a Master's degree in Information Science. You can reach Priamo at priamop@us.ibm.com

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your profile (name, country/region, and company) is displayed to the public and will accompany any content you post. You may update your IBM account at any time.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=WebSphere
ArticleID=31735
ArticleTitle=Identifying memory leaks with the WebSphere Studio Profiler and the JDK Heapdump utility
publish-date=11092004
author1-email=jiwu2@us.ibm.com
author1-email-cc=
author2-email=priamop@us.ibm.com
author2-email-cc=