The IBM Memory Analyzer Tool (MAT) is my preferred tool for analyzing Java heapdumps and core dumps. Sometimes you'll see a dump where there are no obvious causes of high memory usage in the dominator tree nor the top consumers report - the two places I recommend going to first when investigating memory. This post will show how to do advanced analysis using the histogram, retained sets, and incoming references by class.
Here is a dump retaining 4.2GB of Java heap without any large dominators:
The top consumers report is equally uninteresting:
The leak suspects report is slightly more interesting. The suspect is a set of 730 instances of HashMap retaining 2.26GB; however, each individual HashMap is no more than 57MB:
Where do we go from here? We know it's something in HashMaps but there isn't a particular HashMap to look at. Let's go to the class histogram which shows heap usage grouped by class:
Click the little calculator and select "Calculate Minimum Retained Size (quick approx)" to see approximately how much each class and its instances retain.
Next, right click on HashMap and select "Show Objects by class > incoming references." This will show all of the objects that have references to these HashMaps and group the objects by class:
As we expand the top level element, again we'll want to calculate minimum retained size and look for the class and its instances that retains the most. In this case, it is a set of 4,933 instances of PageContextImpl retaining about 2GB of heap.
This is far enough, but just one last step will be interesting which is to right click on PageContextImpl and choose Show Retained Set:
This shows a histogram by class of the set of objects retained by the selection. We can see that most of the memory held by the PageContextImpl and HashMap objects is character arrays. This lines up with the histogram we saw for the whole heap above, and we could have just as quickly gotten to the root cause by simply starting at the histogram and showing incoming references by class on the top element.