Java – How do I find memory leaks in my Java application

How do I find memory leaks in my Java application… here is a solution to the problem.

How do I find memory leaks in my Java application

This is a follow-up issue to my previous question HERE. I witnessed a memory leak in my Java application. Initially, I thought leaking the server components of the app to self. But according to the advice of others, this is not the case.

I used a tool to dump heap memory and visualize it using JProfiler. Apparently this is due to my suspicion of HashMaps. But I’m not sure because I’m not familiar with how to interpret dumps.

enter image description here

Here is a short snippet of my application structure (it caches some text data every 15 minutes to quickly retrieve the server thread).

What causes the leakage problem? And how to identify it from the dump below?
Apparently there are some leaks in the way I execute new Object() and HashMap.put()?!

First entry/main class. Here, I launched 7 main HashMaps, each mapping one key (now only one – eventually there will be 16 keys) to a time-series NavigableMap of about 4000 a line of JSON string.

public class MyCache {
        static HashMap <String, NavigableMap <Long, String>> map1= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map2= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map3= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map4= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map5= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map6= new HashMap <String, NavigableMap <Long, String>> ();
        static HashMap <String, NavigableMap <Long, String>> map7= new HashMap <String, NavigableMap <Long, String>> ();

public static void main(String[] args) throws Exception {
    new Server();
    new Aggregation();
    }
}

Then in Aggregation(), I take some text from the HTTP resource, convert them to JSON strings, cache them in some temporary NavigableMaps, and put them in the main HashMap (so the refresh doesn’t affect the server much).

public class Aggregation {
    static NavigableMap <Long, String> map1Temp= new ConcurrentSkipListMap <Long, String> ();;
    static NavigableMap <Long, String> map2Temp = new ConcurrentSkipListMap <Long, String> ();
    static NavigableMap <Long, String> map3Temp= new ConcurrentSkipListMap <Long, String> ();
    static NavigableMap <Long, String> map4Temp= new ConcurrentSkipListMap <Long, String> ();
    static NavigableMap <Long, String> map5Temp = new ConcurrentSkipListMap <Long, String> ();
    static NavigableMap <Long, String> map6Temp = new ConcurrentSkipListMap <Long, String> ();
    static NavigableMap <Long, String> map7Temp = new ConcurrentSkipListMap <Long, String> ();

public Aggregation(){

 loop to cache last 15 mins
while (true) {
            logger.info("START REFRESHING ...");
    for (int i = 0; i < mylist.size(); i++) {
        long startepoch = getTime(mylist.get(i).time);
        MyItem m = mylist.get(i);
        String index=(i+1)+"";

process1(index, m.name, startepoch);
        adds to map1Temp
        process2(index, m.name, startepoch);
        adds to map2Temp
        process3(index, m.name, startepoch);
        adds to map3Temp
        process4(index, m.name, startepoch);
        adds to map4Temp
        process5(index, m.name, startepoch);
        adds to map5Temp
        process6(index, m.name, startepoch);
        adds to map6Temp
        process7(index, m.name, startepoch);
        adds to map7Temp
        }

then `put` them in the main `HashMap` all at-once:
            MyCache.map1.put(channel, new ConcurrentSkipListMap <Long, String> (map1Temp));
            MyCache.map2.put(channel, new ConcurrentSkipListMap <Long, String> (map2Temp));
            MyCache.map3.put(channel, new ConcurrentSkipListMap <Long, String>(map3Temp));
            MyCache.map4.put(channel, new ConcurrentSkipListMap <Long, String>(map4Temp));
            MyCache.map5.put(channel, new ConcurrentSkipListMap <Long, String> (map5Temp));
            MyCache.map6.put(channel, new ConcurrentSkipListMap <Long, String> (map6Temp));
            MyCache.map7.put(channel, new ConcurrentSkipListMap <Long, String> (map7Temp));

printing the size of all Hashmap entries. They don't grow :-/
logger.info("\t"+"map1.size(): "+MyCache.map1.get(key).size());
logger.info("\t"+"map2.size(): "+MyCache.map2.get(key).size());
and other 5...        

then clear the temp maps so they don't grow over and over
            map1Temp.clear();
            map2Temp.clear();
            map3Temp.clear();
            map4Temp.clear();
            map5Temp.clear();
            map6Temp.clear();
            map7Temp.clear();
    }
sleep for 15 min until next caching cycle
Thread.sleep(cacheEvery*1000*60);
}

Solution

The memory analyzer tells you that you have 3 huge HashMap data structures that take up about 8GB of RAM… Include the closure key and value objects they reference. It looks like they could be maps of maps.

This could be evidence of a memory leak in your country. Your application is adding more and more entries to the map data structure and is (presumably) not removing them. This is a form of memory leak.

(Note that this is part of the code that you didn’t show us in the previous question…)

Related Problems and Solutions