This is a follow-up question from my previous question HERE. I was witnessing memory leaks in my Java application. Initially, I was thinking that the leak is coming from the Server component of my application. But as per other's suggestion, it wasn't.
I used a tool to dump the heap memory and visualize it with JProfiler
. Apparently it is due to my suspected HashMaps
. But I'm not sure as I'm not familiar how to interpret the dump.
Here is a brief snippet of my application's structure (it is caching some text data every 15 mins for fast retrieval of a server thread).
What is causing the leak problem? And how to identify it from the dump below?
Apparently the way I do new Object()
and HashMap.put()
has some leaking problems?!
First starter class/main. Here I initiate 7 main HashMaps
, each mapping a key (right now only one- eventually will have 16 keys) to a time-series NavigableMap
of around 4000 one-liner JSON
Strings.
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();
}
}
And then in Aggregation()
, I get some texts from a HTTP resource, convert them to JSON strings, and cache them in some temporary NavigableMaps
, then put them in the main HashMap
(so refreshing won't affect 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);
}
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 ...)