java - 如何在我的 Java 应用程序中查找内存泄漏

标签 java memory-leaks heap-memory jprofiler jhat

这是我之前问题 HERE 的后续问题.我目睹了我的 Java 应用程序中的内存泄漏。最初,我认为泄漏来 self 的应用程序的服务器组件。但按照其他人的建议,事实并非如此。

我使用了一个工具来转储堆内存并用 JProfiler 可视化它.显然这是由于我怀疑 HashMaps .但我不确定,因为我不熟悉如何解释转储。

enter image description here

这是我的应用程序结构的一个简短片段(它每 15 分钟缓存一些文本数据以快速检索服务器线程)。

导致泄漏问题的原因是什么?以及如何从下面的转储中识别它? 显然我的方式new Object()HashMap.put()有一些泄漏问题?!

第一个入门类/主类。这里我发起7个主要HashMaps ,每个映射一个键(现在只有一个 - 最终将有 16 个键)到时间序列 NavigableMap大约 4000 个单行 JSON字符串。

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 中, 然后将它们放在主 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 ...包括它们引用的闭包键和值对象。看起来它们可能是 map 的 map 。

这可能是您内存泄漏的证据。您的应用程序正在向 map 数据结构中添加越来越多的条目,并且(大概)没有删除它们。这是内存泄漏的一种形式。

(请注意,这是您在上一个问题中没有向我们展示的部分代码...)

关于java - 如何在我的 Java 应用程序中查找内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55428131/

相关文章:

java - Android 中的 `Unknown` ( `Other` ) 内存泄漏?

ajax - 谷歌地图 API v3 内存泄漏

c++ - 为什么要在堆中创建全局对象?

java - 如何在 Ubuntu 上将 Java 作为服务运行?

java - 使用 Realm 浏览器在 Mac 上查看 Realm 文件的加密 key

java - 强制两个相似的类表现得好像它们在 Java 中是多态的

java - 使用 JNI 将 Java Collection<Integer> 类型转换为 R 对象

android - 如何使用探查器查找内存泄漏

c - 内存块/页

java - JVM YoungGen 0%, Perm Gen 99%, OldGen Full