【问题标题】:java ioexception error=24 too many files openjava ioexception 错误=24 打开的文件太多
【发布时间】:2012-07-05 10:48:00
【问题描述】:

我正在编写一个需要读取/写入大量文件的遗传算法。 GA 的适应度测试正在调用一个名为 gradif 的程序,该程序将一个文件作为输入并生成一个文件作为输出。

一切正常,除非我使种群规模和/或遗传算法的总代数过大。然后,经过这么多代,我开始得到这个:java.io.FileNotFoundException: testfiles/GradifOut29 (Too many open files)。 (对于许多不同的文件,我反复得到它,索引29 只是我上次运行它时第一个出现的那个)。这很奇怪,因为在第一代或第二代之后我没有收到错误,而是在经过大量代之后,这表明每一代都会打开更多它不会关闭的文件。但据我所知,我正在关闭所有文件。

代码的设置方式是main()函数在Population类中,Population类包含Individuals的数组。这是我的代码:

输入文件的初始创建(它们是随机访问的,因此我可以在多代中重复使用同一个文件)

files = new RandomAccessFile[popSize];

for(int i=0; i<popSize; i++){
    files[i] = new RandomAccessFile("testfiles/GradifIn"+i, "rw");
}

整个程序结束时:

for(int i=0; i<individuals.length; i++){
    files[i].close();
}

Individual的体能测试里面:

FileInputStream fin = new FileInputStream("testfiles/GradifIn"+index);
FileOutputStream fout = new FileOutputStream("testfiles/GradifOut"+index);
Process process = Runtime.getRuntime().exec ("./gradif");
OutputStream stdin = process.getOutputStream();
InputStream stdout = process.getInputStream();

那么,以后……

try{
      fin.close();
  fout.close();
  stdin.close();
  stdout.close();
      process.getErrorStream().close();
}catch (IOException ioe){
    ioe.printStackTrace();
}

然后,我在文件后面附加一个“END”,以便于解析它们。

FileWriter writer = new FileWriter("testfiles/GradifOut"+index, true);
writer.write("END");
try{
   writer.close();
}catch(IOException ioe){
   ioe.printStackTrace();
}

我对@9​​87654336@ 的标准输入和标准输出重定向来自this answer。我尝试使用try{close()}catch{} 语法来查看关闭任何文件是否有问题(没有),我从this answer 得到。

还应注意Individuals 的体能测试同时运行。

更新:我实际上已经能够将其范围缩小到exec() 调用。在我最近的一次运行中,我第一次遇到麻烦的是第 733 代(人口规模为 100)。为什么前几代还好?我不明白为什么,如果没有泄漏,算法应该能够通过前几代但在后几代失败。如果有泄漏,那么它是从哪里来的?

UPDATE2:在试图弄清楚这里发生了什么时,我希望能够(最好是实时地)查看 JVM 在任何给定点打开了多少文件。有没有简单的方法可以做到这一点?

【问题讨论】:

  • @Thierry 我尽力做到了,我可以在终端中反复这样做。但是有没有什么方法可以让我设置一些东西来实时显示 lsof 的文件数,而我不必继续混合“向上,输入”键?
  • 是的,这是监视命令:“监视。定期执行程序,全屏显示输出。”。默认间隔为 2 秒,但您可以更改它。

标签: java file io ioexception


【解决方案1】:

也许将你所有的动作都放在循环中是个好主意:

while(selection_ of_file.hasNext()){
File are new randomFile
open inputFile
open outPufile
read from inputFile
write to outputFile
close inputFile
close outputFile
}

【讨论】:

    【解决方案2】:

    也尝试关闭错误流:

    process.getErrorStream().close();
    

    编辑: 那么事实上你也应该阅读它,因为错误流上的缓冲区已满会阻塞子进程。

    在此处查看 StreamGobbler 实现: Need sample Java code to run a shellscript

    编辑 2: 是否存在人口规模(足够小),无论代数如何,您都不会遇到问题?如果是这种情况,您可能不会再泄漏打开的文件/流。

    在这种情况下,您有两种解决方案:

    • 要么重写您的算法,以免同时打开所有填充文件
    • 或者增加允许打开文件的最大数量。请参阅here 了解一些方法

    【讨论】:

    • 原来就是这样 - 我关闭了错误流,现在它可以正常工作了。谢谢!
    【解决方案3】:

    您似乎在 linux(或某些类 unix 操作系统)上运行。您可以使用类似“lsof”的命令来确定您的应用程序在收到错误时打开了哪些文件。

    【讨论】:

    • 我看过了。打开文件的列表似乎是它应该的样子。同样,这不会是一个问题,除非该错误发生在数代之后(例如,50 代)。这对我来说意味着每一代它都会打开更多文件而不是关闭以前的文件,但情况似乎并非如此。
    • @MattS - 您查看过系统是否有某个 other 进程正在消耗所有打开的文件?
    • 打开了一堆其他文件,但这是在服务器上运行的。
    【解决方案4】:

    如果您确定要关闭所有文件等,可以尝试提高 ulimit。我曾经遇到过一个问题,Java 程序一直碰到 ulimit 上限。增加它解决了我的问题。我认为它可能需要重新启动服务器,因为它是内核参数。

    【讨论】:

    • 但这并没有解决这样的问题,即如果我能做到即使只是第一代,那么我应该能够让它超过任何数量的世代。
    猜你喜欢
    • 2011-05-16
    • 1970-01-01
    • 2011-01-03
    • 1970-01-01
    • 1970-01-01
    • 2016-07-18
    • 2015-11-30
    • 1970-01-01
    相关资源
    最近更新 更多