11

在我的程序中,关闭一个 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
4

2 回答 2

8

就我而言,原来是我的机器上安装了 McAfee 防病毒软件。我必须安装它(公司政策)...

如果我禁用按访问扫描,问题也会出现。

于 2011-01-22T17:48:55.517 回答
0

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

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

-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 X 上的 /var/tmp (或其他任何名称)中创建文件,因此使用内存文件系统而不是基于磁盘的文件系统。

于 2011-01-22T17:26:25.867 回答