How to Find a Java Memory Leak

How to find a Java Memory Leak

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.

How to find memory leaks in my Java application

The memory analyser is telling you that you have 3 hulking great HashMap data structures occupying about 8GB of RAM ... including the closure key and value objects they refer to. It looks like they might be maps of maps.

That is probably the evidence of your memory leak. Your application is adding more, and more entries to the map data structures, and (presumably) not removing them. That is a form of memory leak.

(Note this is in part of the code that you didn't show us in your previous question ...)

Finding Java memory leak when not all used heap is reachable from threads

I too faced the problem with memory leaks at our site,

Use yourkit java profiler which provide lots of information and with its ability you can have a wider image where all the memory is being utilized.

You can find a great tutorial Find Java Memory Leaks with the above tool.

Your question,

"What kind of Objects are there that are not reachable from an instance of java.lang.Thread other then Objects in the Finalizer Queue and unreferenced objects pending GC?"

There are four kinds of object,

  1. Strong reachable, objects that can be reached directly via references from live objects
  2. Weak/Soft reachable, objects that are having weak/Soft reference associated with them
  3. Pending Finalization, objects that are pending for finalization and whose reference can be reached through finalizer queue
  4. Unreachable these are objects that are unreachable from GC roots, but not yet collected

Besides these JVM also uses Native memory whose information you can find on IBM Heap and native memory use by the JVM and Thanks for the memory and according to YourKit the JVM Memory Structure has Non-Heap Memory whose definition according to them is

Also, the JVM has memory other than the heap, referred to as non-heap memory. It is created at the JVM startup and stores per-class structures such as runtime constant pool, field and method data, and the code for methods and constructors, as well as interned Strings.

In an interview I was asked how do you detect memory leak in Java?

Good topic!

You need to monitor Java memory consumption first.

The simplest way to do this is to use jstat utility that comes with every JVM.

jstat -gcutil <process_id> <timeout>

It will report memory consumption for each generation (Young, Eldery and Old) and garbage collection times (Young and Full).

As soon as you spot that Full Garbage Collection is executed too often and takes too much time, you can assume that application is leaking memory.

Then you need to create a memory dump using jmap utility:

jmap -dump:live,format=b,file=heap.bin <process_id>

Then you need to analyse heap.bin file with Memory Analyser, Eclipse Memory Analyzer (MAT) for example.

MAT will analyze the memory and provide you suspect information about memory leaks.

Java - How to locate the reason for memory leaks with jmap

I have solved this problem with the help of an internal profiling tool. Sorry that I can't share the tool with the public. The comments of this question are very helpful.

I summarized the comments below:

1) Take a heap dump and analyze it with MAT

2) Use an allocation profiler, e.g. Mission Control or async-profiler

3) Use VisualVM to analyse a heap dump or use Mission Control to record allocations. Note: if you reduce the TLAB size you get more fine grade samples.

4) BTW Object[] are more likely being allocated in ArrayList. Give their large average size I suspect your ArrayList are growing dynamically (and large ~7.5K reference each) This places them in tenured space making cleaning them up harder.

In fact, it turns out that the leak is caused by thread-local ArrayDeques, each of which keeps growing its size without being properly cleared.

As @PeterLawrey points out, a large Object[] might indicate a growing ArrayList or ArrayDeque or something like. This advice is very helpful. Thanks again!

Causes of memory leak in java

However, this question is far too crude to get a completely correct answer here. I have only shown you common behavior patterns.

What is a memory leak?

A Memory Leak is a situation when there are objects present in the heap that are no longer used, but the garbage collector is unable to remove them from memory and, thus they are unnecessarily maintained. A memory leak is bad because it blocks memory resources and degrades system performance over time.

What causes memory leaks in Java?

The first scenario that might cause a Java memory leak is referencing a heavy object with a static field. We created our ArrayList as a static field – which will never be collected by the JVM Garbage Collector during the lifetime of the JVM process, even after the calculations it was used for are done.

Symptoms of a Memory leak:

Works fast at first, but slows over time.

  • Works fine with small data sets, severe performance issues with large data sets
  • Ever increasing Old-Generation memory usage in your JVM
  • Out-of-Memory Heap errors in your JVM
  • Spontaneous crashes.

Common memory leaks:

File/Text buffers not closed.

Hash maps keeping references alive if equals() and hashcode() are not implemented, e.g.

import java.util.Map;
public class MemLeak {
public final String key;
public MemLeak(String key) {
this.key = key;
}

public static void main(String args[]) {
try {
Map map = System.getProperties();
for(;;) { map.put(new MemLeak(&quot;key&quot;), &quot;value&quot;); }
}
catch(Exception e) { e.printStackTrace(); }
}
}

How to fixing them?

There are two approaches. The first is a 'quick fix' attempt. If that fails then you'll have to go down the long road.

  1. Quick fix: Eclipse Memory Leak Warnings (catches some leaks)
  2. Manually disable & enable parts of your code and observe memory usage of your JVM using a JVM tool like VisualVM (or Jconsole, or Thermostat).

How to find the line of memory leak in Memory Analyze Tool in Java

If you only have an HPROF heap dump, then this information is not available. You need a profiling agent that records allocation stack traces for each allocation.

For example, JProfiler has this capability. Activate allocation recording in the session startup dialog and then take a heap dump.

In the "Classes" view of the heap walker, select "char[]" and create a new object set. Then go to the "Allocations" tab of the heap walker, and check the cumulated stack traces of all such allocations.

Sample Image

Disclaimer: My company develops JProfiler.



Related Topics



Leave a reply



Submit