如何在我的 Java 应用程序中查找内存泄漏
How to find memory leaks in my Java application
这是我上一个问题 HERE 的后续问题。我在我的 Java 应用程序中目睹了内存泄漏。最初,我认为泄漏来自我的应用程序的服务器组件。但按照其他人的建议,事实并非如此。
我使用了一个工具来转储堆内存并用JProfiler
可视化它。显然是因为我怀疑HashMaps
。但我不确定,因为我不熟悉如何解释转储。
这是我的应用程序结构的一个简短片段(它每 15 分钟缓存一些文本数据以快速检索服务器线程)。
是什么导致了泄漏问题?以及如何从下面的转储中识别它?
显然我做 new Object()
和 HashMap.put()
的方式有一些泄漏问题?!
首发class/main。在这里,我启动了 7 个主要 HashMaps
,每个映射一个键(现在只有一个 - 最终将有 16 个键)到大约 4000 个单行 JSON
字符串的时间序列 NavigableMap
。
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();
}
}
然后在 Aggregation()
中,我从 HTTP 资源中获取一些文本,将它们转换为 JSON 字符串,并将它们缓存在一些临时 NavigableMaps
中,然后将它们放入main HashMap
(所以刷新不会对服务器造成太大影响)。
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);
}
内存分析器告诉您,您有 3 个庞大的 HashMap 数据结构,占用大约 8GB 的 RAM ...包括它们引用的闭包键和值对象。看起来它们可能是地图的地图。
这可能是你内存泄漏的证据。您的应用程序正在向地图数据结构中添加越来越多的条目,并且(大概)没有删除它们。这是内存泄漏的一种形式。
(请注意,这是您在上一个问题中没有向我们展示的部分代码...)
这是我上一个问题 HERE 的后续问题。我在我的 Java 应用程序中目睹了内存泄漏。最初,我认为泄漏来自我的应用程序的服务器组件。但按照其他人的建议,事实并非如此。
我使用了一个工具来转储堆内存并用JProfiler
可视化它。显然是因为我怀疑HashMaps
。但我不确定,因为我不熟悉如何解释转储。
这是我的应用程序结构的一个简短片段(它每 15 分钟缓存一些文本数据以快速检索服务器线程)。
是什么导致了泄漏问题?以及如何从下面的转储中识别它?
显然我做 new Object()
和 HashMap.put()
的方式有一些泄漏问题?!
首发class/main。在这里,我启动了 7 个主要 HashMaps
,每个映射一个键(现在只有一个 - 最终将有 16 个键)到大约 4000 个单行 JSON
字符串的时间序列 NavigableMap
。
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();
}
}
然后在 Aggregation()
中,我从 HTTP 资源中获取一些文本,将它们转换为 JSON 字符串,并将它们缓存在一些临时 NavigableMaps
中,然后将它们放入main HashMap
(所以刷新不会对服务器造成太大影响)。
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);
}
内存分析器告诉您,您有 3 个庞大的 HashMap 数据结构,占用大约 8GB 的 RAM ...包括它们引用的闭包键和值对象。看起来它们可能是地图的地图。
这可能是你内存泄漏的证据。您的应用程序正在向地图数据结构中添加越来越多的条目,并且(大概)没有删除它们。这是内存泄漏的一种形式。
(请注意,这是您在上一个问题中没有向我们展示的部分代码...)