关闭RandomAccessFile有时需要45秒

时间:2011-01-21 15:54:41

标签: java osx-snow-leopard jdk1.6 random-access

在我的程序中,关闭java.util.RandomAccessFile有时需要45秒(好吧,几乎完全是:在44.998和45.003秒之间)。该程序创建和关闭许多小文件。通常关闭文件非常快(在0到0.1秒之间)。如果我调试程序,它将停留在本机方法RandomAccessFile.close0。

使用FileOutputStream而不是RandomAccessFile时也会出现同样的问题(在这种情况下,程序在本机方法FileOutputStream.close0中被阻止)。

有人知道那可能是什么吗?你可以在你的系统上重现这个问题(我只能在Mac上重现它,而不是在Windows XP上重现;我还没有在Linux上测试过)?


更新2:

这似乎只发生在Mac OS X上。我使用的是JDK 1.6.0_22-b04。它发生在32位和64位上。在Windows XP上似乎没有发生。

我的测试用例是:

import java.io.File;
import java.io.RandomAccessFile;
public class TestFileClose {
    public static void main(String... args) throws Exception {
        for (int i = 0; i < 100000; i++) {
            String name = "test" + i;
            RandomAccessFile r = new RandomAccessFile(name, "rw");
            r.write(0);
            long t = System.currentTimeMillis();
            r.close();
            long close = System.currentTimeMillis() - t;
            if (close > 200) {
                System.out.println("closing " + name +
                        " took " + close + " ms!");
            }
            if (i % 2000 == 0) {
                System.out.println("test " + i + "/100000");
            }
            new File(name).delete();
        }
    }
}

我机器上的输出示例:

test 0/100000
test 2000/100000
test 4000/100000
test 6000/100000
test 8000/100000
test 10000/100000
closing test10030 took 44998 ms!
test 12000/100000
test 14000/100000
test 16000/100000
closing test16930 took 44998 ms!
test 18000/100000
test 20000/100000

2 个答案:

答案 0 :(得分:7)

可以在我的计算机上安装McAfee防病毒软件。我不得不安装它......但是如果我禁用了按访问扫描,问题也会出现。

要想验证它不是防病毒软件,有人会在他的机器上重复测试(没有防病毒软件)并且我猜测会遇到同样的问题。

答案 1 :(得分:0)

可能是垃圾收集活动,由打开/关闭大量RandomAccessFile个对象触发; 45秒内可能没有任何魔力 - 它可能只是你的机器上的JVM遍历堆清理对象以释放的时间。话虽如此,45秒是非常长的GC暂停;我最近工作的一个应用程序总是遭受大约11秒的完整GC。

尝试使用 JConsole JVisualVM 监控您的程序,或者在启动程序时尝试添加以下选项:

-verbose:gc -Xloggc:gc.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps

然后查看生成的 gc.log 文件,了解应用程序的停止时间;如果您设置代码以打印时间戳,则可以将close()行为与特定的GC活动联系起来:

...
if (close > 200) {
    System.out.println(new Date());
    System.out.println("closing " + name +
                    " took " + close + " ms!");
}
...

如果它与GC相关,则在 gc.log 文件中,您将在程序输出文件的时间戳附近查找完整垃圾收集和/或应用程序停止时间。

修改堆设置(-Xmx=...XX:MaxPermSize=...)可能会为您提供完全不同的个人资料。

另一方面,如果它是一个临时文件,请尝试使用File file = File.createTempFile(prefix, suffix)并将其传递到RandomAccessFile - 这可能会在OS上创建/ var / tmp(或其所谓的任何文件)中的文件X,因此使用内存文件系统而不是基于磁盘的文件系统。