Java文件I / O性能随着时间的推移而减少

时间:2008-12-04 21:31:52

标签: java windows performance file io

我正在尝试使用Java 5.0 x64(在Windows XP上)执行大文件(~4GB)的一次性读取。

最初文件读取速度非常快,但吞吐量逐渐减慢,随着时间的推移,我的机器似乎反应迟钝。

我使用ProcessExplorer来监控文件I / O统计信息,看起来这个过程最初读取的速度为500MB /秒,但这个速率会逐渐下降到20MB /秒左右。

有关维护文件I / O速率的最佳方法的任何想法,尤其是使用Java读取大型文件时?

这是一些测试代码,显示“间隔时间”继续增加。只需传递一个至少500MB的文件。

import java.io.File;
import java.io.RandomAccessFile;

public class MultiFileReader {

public static void main(String[] args) throws Exception {
    MultiFileReader mfr = new MultiFileReader();
    mfr.go(new File(args[0]));
}

public void go(final File file) throws Exception {
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    long fileLength = raf.length();
    System.out.println("fileLen: " + fileLength);
    raf.close();

    long startTime = System.currentTimeMillis();
    doChunk(0, file, 0, fileLength);
    System.out.println((System.currentTimeMillis() - startTime) + " ms");
}

public void doChunk(int threadNum, File file, long start, long end) throws Exception {
    System.out.println("Starting partition " + start + " to " + end);
    RandomAccessFile raf = new RandomAccessFile(file, "r");
    raf.seek(start);

    long cur = start;
    byte buf[] = new byte[1000];
    int lastPercentPrinted = 0;
    long intervalStartTime = System.currentTimeMillis();
    while (true) {
        int numRead = raf.read(buf);
        if (numRead == -1) {
            break;
        }
        cur += numRead;
        if (cur >= end) {
            break;
        }

        int percentDone = (int)(100.0 * (cur - start) / (end - start));
        if (percentDone % 5 == 0) {
            if (lastPercentPrinted != percentDone) {
                lastPercentPrinted = percentDone;
                System.out.println("Thread" + threadNum + " Percent done: " + percentDone + " Interval time: " + (System.currentTimeMillis() - intervalStartTime));
                intervalStartTime = System.currentTimeMillis();
            }
        }
    }
    raf.close();
}
}

谢谢!

5 个答案:

答案 0 :(得分:10)

我非常怀疑你真的每秒从你的磁盘获得500MB。有可能是操作系统缓存了数据 - 而且当真正击中磁盘时,每秒20MB就会发生这种情况。

这很可能在Vista资源管理器的磁盘部分中可见 - 而低技术的方法是监听磁盘驱动器:)

答案 1 :(得分:1)

根据您的具体硬件和正在发生的其他情况,您可能需要合理努力才能做到超过20MB /秒。

我想也许你真的不怎么完全超出规模500MB /秒......

你有什么希望,并且你检查过你的特定驱动器在理论上是否具备它的能力?

答案 2 :(得分:1)

Java垃圾收集器可能成为瓶颈。

我会使缓冲区更大并且是类的私有,因此它被重用而不是每次调用doChunk()时分配。

public class MultiFileReader {

   private byte buf[] = new byte[256*1024];

   ...

}

答案 3 :(得分:0)

您可以使用JConsole监控您的应用,包括内存使用情况。 500 MB /秒听起来很不错。

有关所使用的实现和VM参数的更多信息会有所帮助。

答案 4 :(得分:0)

检查 static void read3()抛出IOException {

        // read from the file with buffering
        // and with direct access to the buffer

        MyTimer mt = new MyTimer();
        FileInputStream fis = 
                     new FileInputStream(TESTFILE);
        cnt3 = 0;
        final int BUFSIZE = 1024;
        byte buf[] = new byte[BUFSIZE];
        int len;
        while ((len = fis.read(buf)) != -1) {
            for (int i = 0; i < len; i++) {
                if (buf[i] == 'A') {
                    cnt3++;
                }
            }
        }
        fis.close();
        System.out.println("read3 time = " 
                                + mt.getElapsed());
    }

来自http://java.sun.com/developer/JDCTechTips/2002/tt0305.html

最佳缓冲区大小可能取决于操作系统。 你的可能很小。