1

抱歉,我无法发布代码,但我有一个缓冲读取器,其缓冲区大小设置为 50000000 字节。它可以正常工作半小时,硬盘灯每两分钟左右闪烁一次,读取大量数据,然后在 CPU 处理数据时再次安静。但是大约半小时后(这是一个非常大的文件),硬盘开始抖动,就好像它一次读取一个字节一样。它仍然在同一个循环中,我想我检查了空闲内存以排除交换(堆大小是默认值)。

可能不会得到任何有用的答案,但值得一试。

好的,我已将堆大小更改为 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(" ");
    }
4

6 回答 6

1

您是否尝试过删除缓冲区大小并使用默认值进行尝试?

于 2011-01-02T02:33:00.817 回答
1

可能不是文件缓冲不起作用,而是您的程序使用了足够的内存,以至于您的虚拟内存系统正在将页面交换到磁盘。如果您尝试使用较小的缓冲区大小会发生什么?更大的呢?

于 2011-01-02T02:33:21.680 回答
1

我敢打赌,你的堆空间已经用完了,而且你被卡在背靠背的 GC 上。您是否对应用程序进行了概要分析以查看在那段时间发生了什么?另外,尝试使用 -verbose:gc 运行以查看垃圾收集。您也可以尝试从更大的堆开始,例如“

-Xms1000m -Xmx1000m

这将为您提供 1gb 的堆,因此如果您确实使用了所有这些,那么它应该比现在发生的要晚得多。

于 2011-01-02T02:36:04.500 回答
1

在我看来,如果您正在阅读的文件非常大,那么以下几行可能会导致文件的很大一部分通过 StringBuilder 复制到内存中。如果进程的内存占用变得太大,你可能会交换和/或让你的垃圾收集器陷入困境。

...
words.append(nextLine);
words.append(" ");
于 2011-01-02T10:14:00.820 回答
0

希望这可能会有所帮助:http ://www.velocityreviews.com/forums/t131734-bufferedreader-and-buffer-size.html

于 2011-01-02T02:28:57.663 回答
0

在你假设 Java 和读取 IO 有问题之前,我建议你编写一个简单的程序,它只是尽可能快地读取文件。无论使用默认缓冲的文件大小如何,您都应该能够以 20 MB/s 或更高的速度读取文件。您应该能够通过剥离您的应用程序来读取文件来做到这一点。然后您可以向自己证明读取文件需要多长时间。

您已经使用了很多昂贵的操作。也许您应该看看如何使用分析器使解析器更高效。例如

word.substring(0, word.length() - 1) 

是相同的

word

所以第一个 if 子句和第二个是相同的。

于 2011-01-02T10:29:11.270 回答