抱歉,我无法发布代码,但我有一个缓冲区,其缓冲区大小为50000000字节。它可以像你期望的那样工作半小时,硬盘指示灯每两分钟闪烁一次,读取大块数据,然后在CPU处理它时再次静音。但是大约半个小时后(这是一个非常大的文件),硬盘驱动器开始颠簸,好像它一次读取一个字节。它仍处于相同的循环中,我认为我检查了自由ram以排除交换(堆大小是默认值)。
可能不会得到任何有用的答案,但值得一试。
好的我已经将堆大小更改为768mb但仍然没有。有足够的可用内存,java.exe只使用大约300mb。
现在我已对它进行了分析,并且堆保持在大约200MB,远低于可用的容量。 CPU保持在50%。然而硬盘驱动器开始疯狂地捶打。我不知道。我将用c#重写整个内容,这是我的解决方案。
这是代码(它只是一个抛弃的脚本,不是很漂亮):
BufferedReader s = null;
HashMap<String, Integer> allWords = new HashMap<String, Integer>();
HashSet<String> pageWords = new HashSet<String>();
long[] pageCount = new long[78592];
long pages = 0;
Scanner wordFile = new Scanner(new BufferedReader(new FileReader("allWords.txt")));
while (wordFile.hasNext()) {
allWords.put(wordFile.next(), Integer.parseInt(wordFile.next()));
}
s = new BufferedReader(new FileReader("wikipedia/enwiki-latest-pages-articles.xml"), 50000000);
StringBuilder words = new StringBuilder();
String nextLine = null;
while ((nextLine = s.readLine()) != null) {
if (a.matcher(nextLine).matches()) {
continue;
}
else if (b.matcher(nextLine).matches()) {
continue;
}
else if (c.matcher(nextLine).matches()) {
continue;
}
else if (d.matcher(nextLine).matches()) {
nextLine = s.readLine();
if (e.matcher(nextLine).matches()) {
if (f.matcher(s.readLine()).matches()) {
pageWords.addAll(Arrays.asList(words.toString().toLowerCase().split("[^a-zA-Z]")));
words.setLength(0);
pages++;
for (String word : pageWords) {
if (allWords.containsKey(word)) {
pageCount[allWords.get(word)]++;
}
else if (!word.isEmpty() && allWords.containsKey(word.substring(0, word.length() - 1))) {
pageCount[allWords.get(word.substring(0, word.length() - 1))]++;
}
}
pageWords.clear();
}
}
}
else if (g.matcher(nextLine).matches()) {
continue;
}
words.append(nextLine);
words.append(" ");
}
答案 0 :(得分:1)
您是否尝试删除缓冲区大小并使用默认值进行尝试?
答案 1 :(得分:1)
可能不是文件缓冲不起作用,而是程序占用的内存足以使虚拟内存系统页面交换到磁盘。如果尝试使用较小的缓冲区大小会发生什么?怎么样更大?
答案 2 :(得分:1)
我敢打赌,你的堆空间已经不多了而且你正在坚持退回GC。你有没有想过应用程序看看那段时间发生了什么?另外,尝试使用-verbose:gc运行以查看垃圾收集。您也可以尝试从更大的堆开始,例如“
-Xms1000m -Xmx1000m
这将为你提供1GB的堆,所以如果你全部使用它,它应该比当前发生的要晚得多。
答案 3 :(得分:1)
在我看来,如果您正在阅读的文件非常大,那么以下行可能会导致大部分文件通过StringBuilder复制到内存中。如果进程的内存占用空间过大,您可能会将垃圾收集器交换和/或抛弃。
...
words.append(nextLine);
words.append(" ");
答案 4 :(得分:0)
答案 5 :(得分:0)
在您认为Java出现问题并读取IO之前,我建议您编写一个简单的程序,它只是尽可能快地读取文件。无论文件大小如何,您都应该能够以20 MB / s或更高的速度读取文件并使用默认缓冲。您应该可以通过剥离应用程序来只读取文件来完成此操作。然后你可以自己证明阅读文件需要多长时间。
您使用了大量昂贵的操作。也许您应该看看如何使用分析器提高解析器的效率。 e.g。
word.substring(0, word.length() - 1)
与
相同word
所以第一个if子句和第二个是相同的。