2

多くのファイルを読み書きする必要がある遺伝的アルゴリズムを書いています。gradifGA の適合性テストは、ファイルを入力として受け取り、出力としてファイルを生成するというプログラムを呼び出しています。

遺伝的アルゴリズムの人口サイズや総世代数を大きくしすぎた場合を除いて、すべてが機能しています。その後、何世代にもわたって、次のようになりましjava.io.FileNotFoundException: testfiles/GradifOut29 (Too many open files)た。(多くの異なるファイルに対して繰り返し取得します。インデックス29は、前回実行したときに最初に表示されたものにすぎません)。第 1 世代または第 2 世代の後にエラーが発生しないのは奇妙ですが、かなりの量の世代が経過した後です。これは、各世代が閉じないより多くのファイルを開くことを示唆しています。しかし、私が知る限り、すべてのファイルを閉じています。

コードの設定方法は、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();
}

stdin と stdout のリダイレクトは、この回答gradifからのものです。構文を使用して、ファイルを閉じる際に問題があるかどうかを確認してみました (ありませんでした) 。この回答からそれを得ました。try{close()}catch{}

Individuals のフィットネス テストが同時に実行されることにも注意してください。

exec()更新: 私は実際にそれを呼び出しに絞り込むことができました. 最近の実行では、最初に世代 733 (人口サイズ 100) で問題に遭遇しました。なぜ前の世代は大丈夫なのですか?リークがない場合、アルゴリズムは以前の世代を通過できるはずですが、後の世代では失敗する理由がわかりません。また、漏れがあるとすれば、どこから漏れているのでしょうか?

更新 2: ここで何が起こっているのかを把握しようとして、JVM が任意の時点で開いているファイルの数を (できればリアルタイムで) 確認できるようにしたいと考えています。それを行う簡単な方法はありますか?

4

4 に答える 4

1

エラーストリームも閉じてみてください:

process.getErrorStream().close();

編集:エラーストリームでバッファがいっぱいになると子プロセスがブロックされるため、実際にはそれも読む必要があります。

ここでStreamGobblerの実装を見てください:シェルスクリプト を実行するにはサンプルのJavaコードが必要です

編集2:世代数が何であれ、問題が発生しない人口サイズ(十分に小さい)はありますか?その場合は、開いているファイル/ストリームがリークしていない可能性があります。

その場合、2つの解決策があります。

  • すべてのポピュレーションファイルを同時に開いたままにしないようにアルゴリズムを書き直してください
  • または、許可されるオープンファイルの最大数を増やします。それを行ういくつかの方法については、ここを参照してください
于 2012-07-05T07:39:07.507 に答える
1

おそらく、すべてのアクションをループ内に配置することをお勧めします。

while(selection_ of_file.hasNext()){
File are new randomFile
open inputFile
open outPufile
read from inputFile
write to outputFile
close inputFile
close outputFile
}
于 2012-07-05T06:15:55.913 に答える
0

あなたはLinux(またはUNIXのようなオペレーティングシステム)で実行しているようです。「lsof」コマンドのようなものを使用して、エラーが発生したときにアプリケーションが開いているファイルを把握できます。

于 2012-07-05T03:27:23.373 に答える
0

すべてのファイルなどを閉じていることが確実な場合は、ulimit を上げてみてください。Java プログラムが ulimit の上限にぶつかり続けるという問題がありました。それを増やすと、私の問題は解決しました。これはカーネル パラメータであるため、サーバーの再起動が必要になる可能性があると思います。

于 2012-07-06T21:19:59.543 に答える