tags:

views:

7134

answers:

9

How do you find a memory leak in Java (using for example JHat)? I have tried to load the heap dump up in JHat to take a basic look. However I do not understand how I am supposed to be able to find the root reference (ref) or whatever it is called. Basically I can tell that there are several hundred meg of hash table entries ([java.util.HashMap$Entry or something like that), but maps are used all over the place... Is there some way to search for large maps, or perhaps finding general roots of large object trees?

[Edit] Ok, I've read the answers so far but lets just say I am a cheap bastard (meaning I am more interested in learning how to use JHat than to pay for JProfiler). Also JHat is always available since it is part of the JDK. Unless of course there is no way with JHat but brute force, but I can't believe that can be the case.

Also, I do not think I will be able to actually modify (adding logging of all map sizes) and run it for long enough for me to notice the leak.

+1  A: 

Well, there's always the low tech solution of adding logging of the size of your maps when you modify them, then search the logs for which maps are growing beyond a reasonable size.

Mike Stone
A: 

You really need to use a memory profiler that tracks allocations. Take a look at JProfiler - their "heap walker" feature is great, and they have integration with all of the major Java IDEs. It's not free, but it isn't that expensive either ($499 for a single license) - you will burn $500 worth of time pretty quickly struggling to find a leak with less sophisticated tools.

McKenzieG1
+2  A: 

There are tools that should help you find your leak, like JProbe, YourKit, AD4J or JRockit Mission Control. The last is the one that I personally know best. Any good tool should let you drill down to a level where you can easily identify what leaks, and where the leaking objects are allocated.

Using HashTables, Hashmaps or similar is one of the few ways that you can acually leak memory in Java at all. If I had to find the leak by hand I would peridically print the size of my HashMaps, and from there find the one where I add items and forget to delete them.

Tnilsson
A: 

This is another "vote" for JProfiler. It works pretty well for heap analysis, has a decent UI, and works pretty well. As McKenzieG1 says, $500 is cheaper than the amount of time you would otherwise burn looking for the source to these leaks. As far as the price of tools go, it's not bad.

joev
A: 

NetBeans has a built-in profiler.

wbkang
+3  A: 

A tool is a big help.

However, there are times when you can't use a tool: the heap dump is so huge it crashes the tool, you are trying to troubleshoot a machine in some production environment to which you only have shell access, etc.

In that case, it helps to know your way around the hprof dump file.

Look for SITES BEGIN. This shows you what objects are using the most memory. But the objects aren't lumped together solely by type: each entry also includes a "trace" ID. You can then search for that "TRACE nnnn" to see the top few frames of the stack where the object was allocated. Often, once I see where the object is allocated, I find a bug and I'm done. Also, note that you can control how many frames are recorded in the stack with the options to -Xrunhprof.

If you check out the allocation site, and don't see anything wrong, you have to start backward chaining from some of those live objects to root objects, to find the unexpected reference chain. This is where a tool really helps, but you can do the same thing by hand (well, with grep). There is not just one root object (i.e., object not subject to garbage collection). Threads, classes, and stack frames act as root objects, and anything they reference strongly is not collectible.

To do the chaining, look in the HEAP DUMP section for entries with the bad trace id. This will take you to an OBJ or ARR entry, which shows a unique object identifier in hexadecimal. Search for all occurrences of that id to find who's got a strong reference to the object. Follow each of those paths backward as they branch until you figure out where the leak is. See why a tool is so handy?

Static members are a repeat offender for memory leaks. In fact, even without a tool, it'd be worth spending a few minutes looking through your code for static Map members. Can a map grow large? Does anything ever clean up its entries?

erickson
A: 

you may want to check out jconsole. It's also part of the JDK and I have found it helpful to find memory/reference leaks in conjunction with jhat. Also take a look at this blog entry.

JMM
+8  A: 

I use following approach to finding memory leaks in Java. I've used jProfiler with great success, but I believe that any specialized tool with graphing capabilities (diffs are easier to analyze in graphical form) will work.

  1. Start the application and wait until it get to "stable" state, when all the initialization is complete and the application is idle.
  2. Run the operation suspected of producing a memory leak several times to allow any cache, DB-related initialization to take place.
  3. Run GC and take memory snapshot.
  4. Run the operation again. Depending on the complexity of operation and sizes of data that is processed operation may need to be run several to many times.
  5. Run GC and take memory snapshot.
  6. Run a diff for 2 snapshots and analyze it.

Basically analysis should start from greatest positive diff by, say, object types and find what causes those extra objects to stick in memory.

For web applications that process requests in several threads analysis gets more complicated, but nevertheless general approach still applies.

I did quite a number of projects specifically aimed at reducing memory footprint of the applications and this general approach with some application specific tweaks and trick always worked well.

Dima Malenko
Could you tell me how to run the GC manually
Eager Learner
Most (if not all) Java profilers provide you with an option to invoke GC with a click of a button.Or you can call System.gc() from appropriate place in your code.
Dima Malenko
+10  A: 

Questioner here, I got to say getting a tool that does not take 5 minutes to answer any click makes it a lot easier to find potential memory leaks.

Since people are suggesting several tools ( I only tried visual wm since I got that in the JDK and JProbe trial ) I though I should suggest a free / open source tool built on the Eclipse platform, the Memory Analyzer (sometimes referenced as the SAP memory analyzer) available on http://www.eclipse.org/mat/ .

What is really cool about this tool is that it indexed the heap dump when I first opened it which allowed it to show data like retained heap without waiting 5 minutes for each object (pretty much all operations was tons faster than the other tools I tried).

When you open the dump the first screen shows you a pie chart with the biggest objects (counting retained heap) and one can quickly navigate down to the objects that are to big for comfort. It also has a Find likely leak suspects which I reccon can come in handly, but since the navigation was enough for me I did not really get into it.

jwiklund