为什么Java的HashMap的放缓?(Why is Java HashMap slowing do

2019-09-17 07:46发布

我尝试建立与文件的内容的地图,我的代码如下:

    System.out.println("begin to build the sns map....");
    String basePath = PropertyReader.getProp("oldbasepath");
    String pathname = basePath + "\\user_sns.txt";
    FileReader fr;
    Map<Integer, List<Integer>> snsMap = 
            new HashMap<Integer, List<Integer>>(2000000);
    try {
        fr = new FileReader(pathname);
        BufferedReader br = new BufferedReader(fr);
        String line; 
        int i = 1;
        while ((line = br.readLine()) != null) {
            System.out.println("line number: " + i);
            i++;

            String[] strs = line.split("\t");
            int key = Integer.parseInt(strs[0]);
            int value = Integer.parseInt(strs[1]);
            List<Integer> list = snsMap.get(key);
            //if the follower is not in the map
            if(snsMap.get(key) == null) 
                list = new LinkedList<Integer>();
            list.add(value);
            snsMap.put(key, list);
            System.out.println("map size: " + snsMap.size());
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    System.out.println("finish building the sns map....");
    return snsMap;

该方案是在第一速度非常快 ,但得到缓慢得多时打印的信息是:

 map size: 1138338
 line number: 30923602
 map size: 1138338
 line number: 30923603 
 ....

我试图找到两个的System.out.println()子句的理由判断的BufferedReader和HashMap的性能与特点,而不是Java剖析。 有时它需要在获取行号信息后,获取地图大小的信息,有时,它需要一段时间才能得到的行号信息获取地图尺寸之后的信息。 我的问题是:这让我的程序慢? 在BufferedReader中的一个大文件或HashMap的一个大的地图吗?

Answer 1:

如果您是从Eclipse内部测试这个,你应该知道写入标准输出/标准错误的巨大性能损失,由于Eclipse的捕捉控制台认为ouptut。 一个紧密的循环内打印始终是一个性能问题,甚至外面的Eclipse。

但是,如果你正在抱怨是处理30万款后经历了经济放缓,那么我敢打赌,这是一个记忆的问题。 首先,它会减慢由于激烈的GC'ing然后将它与打破OutOfMemoryError



Answer 2:

你必须检查你一些分析工具进行编程,以明白为什么它是缓慢的。 一般文件的访问比内存操作更慢(除非你是在内存受限的和做过多的GC),所以猜测是阅读文件可能较慢这里。



Answer 3:

你异形之前,你不会知道什么是缓慢的,哪些不是。

最有可能的System.out会显示为瓶颈,然后你要没有他们再次剖析。 System.out是,你可以寻找性能瓶颈,因为这样做你通常添加一个更糟糕的瓶颈, 最糟糕的事情。

为你的代码的obivous优化是招行

snsMap.put(key, list);

if声明。 你只需要把这个当你创建了一个新的列表。 否则,将放只是自身替换当前值。

与相关的Java成本Integer对象(尤其是使用Java集合API在整数)在很大程度上是一种内存(因此垃圾回收 !)问题。 您可以通过使用原始的集合,例如有时会显著收益GNU宝库 ,这取决于你如何调整你的代码有效地使用它们。 大多数特罗韦的涨幅都在内存使用情况。 绝对尝试重写代码中使用TIntArrayListTIntObjectMap从GNU宝库。 我会避免链表,太,特别是基本类型。

粗略估计,一个HashMap<Integer, List<Integer>>需要每个条目至少3×16个字节。 双向链表再次需要每个存储的项目至少2 * 16个字节。 1米键+30米值〜1 GB。 无开销包括呢。 与GNU特罗韦TIntObjectHash<TIntArrayList>应该是每个键4个+ 4 + 16字节和每个值的4个字节,所以144 MB。 开销大概是两个相似的。

该特罗韦使用较少的内存的原因是因为该类型专门用于诸如基本值int 。 它们将存储int直接值,从而使用4个字节来存储每个。

一个Java集合HashMap是由许多对象。 它大致是这样的:有Entry对象是指向一个键和值对象的每个。 这是因为仿制药的方式必须是对象,Java中进行处理。 在你的情况下,密钥将是一个Integer对象,使用16个字节(4个字节标志,4个字节的类型,4个字节的实际int值,4个字节的填充)AFAIK。 这些都是32位系统估计。 因此,在一个单一的入口HashMap可能会需要一些16(项)+ 16(整数键)+ 32(但空链表)字节的内存,所有需要考虑进行垃圾回收。

如果你有大量的Integer对象,它只是需要4倍的内存,如果你能使用存储一切int元。 这是一分钱一分货在Java中实现了清洁OOP原则的成本。



Answer 4:

最好的办法是用探查运行您的程序(例如,JProfile),看看哪些部分是缓慢的。 此外调试输出可以减缓你的程序,例如。



Answer 5:

哈希表是不慢,但实际上它的地图中是最快的。 哈希表是唯一的线程安全的地图中,并且可能会很慢,有时。

重要提示:关闭的BufferedReader和文件ü读取数据后,...这可能帮助。

例如:br.close()file.close()

请检查从任务管理器,你的系统进程,有可能是在后台运行,也可能进程。

有时日食是真正的资源重,所以尝试从控制台运行它来检查它。



文章来源: Why is Java HashMap slowing down?