Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/377.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么大型未引用哈希映射会提高Java的性能?_Java_Memory_Memory Management_Hashmap - Fatal编程技术网

为什么大型未引用哈希映射会提高Java的性能?

为什么大型未引用哈希映射会提高Java的性能?,java,memory,memory-management,hashmap,Java,Memory,Memory Management,Hashmap,我有一个性能问题,我无法解决。我正在编写一个Java应用程序,它解析巨大的(>2000万行)文本文件,并将某些信息存储在一个集合中。 我以每百万行的秒数来衡量性能。因为我需要大量内存,所以我通常使用-Xmx6000m和-Xms4000m运行程序 如果我只是运行这个程序,它会在大约6秒钟内解析100万行。但是,经过一些性能调查后,我意识到,如果我在实际解析例程之前添加此代码,性能将提高到每一百万行不到3秒: BufferedReader br = new BufferedReader(new Fi

我有一个性能问题,我无法解决。我正在编写一个Java应用程序,它解析巨大的(>2000万行)文本文件,并将某些信息存储在一个集合中。 我以每百万行的秒数来衡量性能。因为我需要大量内存,所以我通常使用-Xmx6000m和-Xms4000m运行程序

如果我只是运行这个程序,它会在大约6秒钟内解析100万行。但是,经过一些性能调查后,我意识到,如果我在实际解析例程之前添加此代码,性能将提高到每一百万行不到3秒:

BufferedReader br = new BufferedReader(new FileReader("graphs.nt"));
HashMap<String, String> foo = new HashMap<String, String>();
String line;
while ((line = br.readLine()) != null){
    foo.put(line, "foo");
}
foo = null;
br.close();
br = null;
BufferedReader br=newbufferedreader(newfilereader(“graphs.nt”);
HashMap foo=新的HashMap();
弦线;
而((line=br.readLine())!=null){
foo.put(第行“foo”);
}
foo=null;
br.close();
br=null;
graphs.nt文件大约有900万行长。即使我没有将foo设置为null,性能也会持续提高,这主要是为了证明程序实际上没有使用映射

代码的其余部分完全不相关。我使用openrdf sesame的解析器读取不同的(而不是graphs.nt)文件,并将提取的信息存储在另一个对象创建的新哈希集中。 在代码的其余部分,我创建了一个,并向其传递了一个

这真让我困惑。我的猜测是,这以某种方式驱动JVM为我的程序分配更多内存,我可以在运行top时看到提示。如果没有HashMap,它将分配大约1G的内存。如果我初始化HashMap,它将分配>2个gig

我的问题是,这听起来是否合理。创建这么大的对象是否可能为程序分配更多的内存以供以后使用?-Xmx和-Xms不应该控制内存分配吗?或者这里是否还有其他参数可能起作用


我知道这似乎是一个奇怪的问题,而且信息稀少,但这就是我发现的所有与该问题相关的信息。如果有更多有用的信息,我非常乐意提供。

内存和GC肯定会影响性能。如果可能的话,您应该运行Xms==Xmx来禁用调整大小,并在开始时给JVM足够的空间。你的应用程序可以在需要任何主要GC之前退出。

除非你不遗余力地去做,否则,“foo”最终会超出范围并被收集,即使你没有取消指针,即使包含上述代码的方法从未退出。但这将迫使堆变大,这将减少GC的相对开销


(在程序末尾引用“foo”将是一个有趣的实验,以保持它在范围内。)

这听起来像是文件缓存?您的文件“graphs.nt”可能由操作系统或JVM缓存在RAM中。由于性能原因,GC将允许内存消耗增加,如果您在预加载后立即添加强制收集,
System.GC()
,您将能够知道缓存是在JVM中还是在操作系统中发生。

在此之前您是如何做的?添加容量可能会提高效率,因为Map可以更好地将元素分配到bucket中。我不确定我是否理解这个问题。但可能还不清楚:我为“提高性能”而创建的HashMap不是实际应用程序存储数据的HashMap!我基本上是在main方法的开头添加上面的代码,然后运行完全不相关的其余代码。您的意思是说在性能较低的版本中没有发布的代码吗?你在高性能版本中读了两次文件,而在低性能版本中只读了一次?我错过了你在原来的帖子中提到的两个不同的文件;很抱歉。这太奇怪了。你有没有试过分析这两种情况,看看时间会怎样?另外,与额外I/O相关的加速可能与底层环境有关,而不是与Java有关。(顺便问一下,是什么促使您尝试在处理前端处理此代码?)我将读取行替换为25个字符的随机字母数字生成器,因此不再读取文件。性能仍在提高。我还使用-Xint开关运行了“预点火”和“非预点火”代码,这将强制执行解释模式。在这种情况下,没有性能差异。这两种版本都需要65秒才能完成一百万行。我猜这是一个强烈的暗示,它与JIT有关?你是说类似于
System.out.println(foo.keySet().size())?我最后补充说,性能没有下降。无论如何,它不应该超出范围,因为我的主要代码基本上是上面的代码加上一行
新的Parser.parse()
行,开始计算。@feob-是的,应该这样做。如果这没有什么区别,那么可能是因为您“预热”了JITC中的HashMap.put。您可以通过使用其他一些不相关(并且在“真实”代码中未使用)的数据结构替换foo来测试这一点。(顺便说一句,即使是dumbjavac也可能足够聪明地注意到foo没有被引用,并将它的本地var槽循环用于其他用途,如果下面的代码非常复杂,则允许foo超出范围。),实际上,我稍后在代码中使用了哈希集。但即使是这样,“未初始化”代码的性能最终也应该赶上预热代码,不是吗?在运行约30分钟的程序中,情况并非如此。