Java BufferedReader在一段时间后不再缓冲?

Java BufferedReader在一段时间后不再缓冲?,java,bufferedreader,Java,Bufferedreader,很抱歉,我无法发布代码,但我有一个缓冲区大小设置为50000000字节的bufferedreader。它可以像你预期的那样工作半个小时,硬盘指示灯每两分钟左右闪烁一次,读取大量数据,然后在CPU处理数据时再次静音。但大约半个小时后,这是一个非常大的文件,硬盘驱动器开始摇晃,好像一次读取一个字节。它仍然在同一个循环中,我想我检查了空闲ram以排除交换堆大小是默认值 可能不会得到任何有用的答案,但值得一试 好的,我已经将堆大小更改为768mb,但仍然没有更改。有大量的可用内存,java.exe仅使用

很抱歉,我无法发布代码,但我有一个缓冲区大小设置为50000000字节的bufferedreader。它可以像你预期的那样工作半个小时,硬盘指示灯每两分钟左右闪烁一次,读取大量数据,然后在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(" ");
    }

希望这会有所帮助:

希望这会有所帮助:

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

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

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

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

我敢打赌,您的堆空间已经用完,而且您在背对背地执行GC时遇到了困难。您是否对应用程序进行了分析,以了解在此期间发生了什么?此外,请尝试使用-verbose:gc运行以查看垃圾收集的情况。您也可以尝试从更大的堆开始,如

-Xms1000m-Xmx1000m


这将给你1gb的堆,所以如果你真的把这些都用光了,应该比现在要晚很多

我敢打赌,您的堆空间已经用完了,而且您在做背对背的GC时遇到了困难。您是否对应用程序进行了分析,以了解在此期间发生了什么?此外,请尝试使用-verbose:gc运行以查看垃圾收集的情况。您也可以尝试从更大的堆开始,如

-Xms1000m-Xmx1000m


这将给你1gb的堆,所以如果你真的把这些都用光了,应该比现在要晚很多

在我看来,如果您正在读取的文件非常大,那么以下几行可能会导致文件的很大一部分通过StringBuilder复制到内存中。如果进程的内存占用过大,则可能会交换和/或使垃圾收集器陷入旋转状态

...
words.append(nextLine);
words.append(" ");

在我看来,如果您正在读取的文件非常大,那么以下几行可能会导致文件的很大一部分通过StringBuilder复制到内存中。如果进程的内存占用过大,则可能会交换和/或使垃圾收集器陷入旋转状态

...
words.append(nextLine);
words.append(" ");

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

你做了很多昂贵的手术。也许您应该看看如何使用分析器来提高解析器的效率。e、 g

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

word

因此,第一个if子句和第二个if子句是相同的。

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

你做了很多昂贵的手术。也许您应该看看如何使用分析器来提高解析器的效率。e、 g

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

word

因此,第一个if子句和第二个if子句是相同的。

我相信在较小的缓冲区大小默认缓冲区大小时也会发生相同的事情,而且我也非常确定我检查了页面交换,正如我所提到的。我不知道,我的意思是,当我进行解析并读取数据时,问题并没有发生,但我什么也没做。。。但我几乎可以肯定,我检查了交换,它看起来不像是页面交换,它看起来像是有人用非常漂亮的工具敲打硬盘
我相信同样的事情也会发生在较小的缓冲区大小默认缓冲区大小上,而且我也很确定我检查了页面交换,正如我提到的。我不知道,我的意思是,当我进行解析并读取数据时,问题并没有发生,但我什么也没做。。。但我几乎可以肯定我检查了交换,它看起来不像是页面交换,它看起来像是有人用非常小的读取量敲打硬盘。我很好奇:为什么你需要使用一个带50 MB缓冲区的缓冲读卡器?这似乎与整个阅读器实现的设计意图背道而驰,整个阅读器实现的重点是在解析数据时引入数据,而不是读取整个文件。。。。最好集中在这里的设计上……因为一次读取大量数据比读取少量数据效率更高,因为系统调用减少,硬盘磁头必须重新定位等等。我认为您已经采纳了一些一般来说很好的建议,并将其扩展到了极限。这个建议可能适用于64k大小的应用程序缓冲区,而不是256字节或其他大小的应用程序缓冲区,但我可能不会给出更多的建议。无论如何,操作系统都会为你做额外的缓冲,尤其是顺序读取文件。将自己的应用程序缓冲区设置为50 MB最终可能会适得其反,因为您可能会将该内存用于更相关的内容,事实上,听起来您是这样。我没有将其推广到极端,这不是建议,而是从对基础理论和实践的理解中得出的。它之所以相关是因为文件的大小。这完全是一个前瞻性的问题。只需先尝试使用更小的缓冲区大小(实际上是默认值),然后看看问题是否仍然存在。如果它没有发生,你有一个明确的指标。如果是这样的话,我们会想出别的办法。请记住,内存和CPU比IO快得多,因此较小的缓冲区大小不太可能突然影响性能。我很好奇:为什么需要使用具有50 MB缓冲区的缓冲读取器?这似乎与整个阅读器实现的设计意图背道而驰,整个阅读器实现的重点是在解析数据时引入数据,而不是读取整个文件。。。。最好集中在这里的设计上……因为一次读取大量数据比读取少量数据效率更高,因为系统调用减少,硬盘磁头必须重新定位等等。我认为您已经采纳了一些一般来说很好的建议,并将其扩展到了极限。这个建议可能适用于64k大小的应用程序缓冲区,而不是256字节或其他大小的应用程序缓冲区,但我可能不会给出更多的建议。无论如何,操作系统都会为你做额外的缓冲,尤其是顺序读取文件。将自己的应用程序缓冲区设置为50 MB最终可能会适得其反,因为您可能会将该内存用于更相关的内容,事实上,听起来您是这样。我没有将其推广到极端,这不是建议,而是从对基础理论和实践的理解中得出的。它之所以相关是因为文件的大小。这完全是一个前瞻性的问题。只需先尝试使用更小的缓冲区大小(实际上是默认值),然后看看问题是否仍然存在。如果它没有发生,你有一个明确的指标。如果是这样的话,我们会想出别的办法。请记住,内存和CPU比IO快得多,因此较小的缓冲区大小不太可能突然影响性能。