1

グリッド コンピュータでプログラムを実行しようとすると、 (開いているファイル ハンドルが多すぎる)と同様の問題が発生します。このリソースで開いているファイルの総数に対するオペレーティング システムの制限を増やすオプションは使用できません。

例外をキャッチして処理しようとしましたが、例外をキャッチすることはできないようです。例外は、それ自体をFileNotFoundException. 例外がスローされる場所の 1 つは、以下に示すメソッドです。

public static void saveImage(BufferedImage bi, String format, File aFile) {
  try {
    if (bi != null) {
      try {
        //System.out.println("ImageIO.write(BufferedImage,String,File)");
        System.err.println("Not really an error, just a statement to help with debugging");
        ImageIO.write(bi, format, aFile);
      } catch (FileNotFoundException e) {
        System.err.println("Trying to handle " + e.getLocalizedMessage());
        System.err.println("Wait for 2 seconds then trying again to saveImage.");
        //e.printStackTrace(System.err);
        // This can happen because of too many open files.
        // Try waiting for 2 seconds and then repeating...
        try {
          synchronized (bi) {
            bi.wait(2000L);
          }
        } catch (InterruptedException ex) {
          Logger.getLogger(Generic_Visualisation.class.getName()).log(Level.SEVERE, null, ex);
        }
        saveImage(
        bi,
        format,
        aFile);
      } finally {
        // There is nothing to go in here as ImageIO deals with the stream.    
      }
    }
  } catch (IOException e) {
    Generic_Log.logger.log(
    Generic_Log.Generic_DefaultLogLevel, //Level.ALL,
    e.getMessage());
    String methodName = "saveImage(BufferedImage,String,File)";
    System.err.println(e.getMessage());
    System.err.println("Generic_Visualisation." + methodName);
    e.printStackTrace(System.err);
    System.exit(Generic_ErrorAndExceptionHandler.IOException);
  }
}

問題が発生したときに一度報告された System.err のスニペットを次に示します。

Not really an error, just a statement to help with debugging   
java.io.FileNotFoundException: /data/scratch/lcg/neiss140/home_cream_292126297/CREAM292126297/genesis/GENESIS_DemographicModel/0_99/0/data/Demographics/0_9999/0_99/39/E02002367/E02002367_Population_Male_End_of_Year_Comparison_2002.PNG (Too many open files) 
  at java.io.RandomAccessFile.open(Native Method)
  at java.io.RandomAccessFile.(RandomAccessFile.java:216) 
  at javax.imageio.stream.FileImageOutputStream.(FileImageOutputStream.java:53) 
  at com.sun.imageio.spi.FileImageOutputStreamSpi.createOutputStreamInstance(FileImageOutputStreamSpi.java:37) 
  at javax.imageio.ImageIO.createImageOutputStream(ImageIO.java:393) 
  at javax.imageio.ImageIO.write(ImageIO.java:1514) 
  at uk.ac.leeds.ccg.andyt.generic.visualisation.Generic_Visualisation.saveImage(Generic_Visualisation.java:90) 
  at uk.ac.leeds.ccg.andyt.generic.visualisation.Generic_Visualisation$ImageSaver.run(Generic_Visualisation.java:210) 
  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:439) 
  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303) 
  at java.util.concurrent.FutureTask.run(FutureTask.java:138) 
  at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) 
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) 
  at java.lang.Thread.run(Thread.java:662)

この問題を回避するためのアイデアはいくつかありますが、何が問題なのか知っている人はいますか?

(この質問への回答として、この質問のバージョンを投稿しようとしましたが、モデレーターによって削除されました。)

4

1 に答える 1

1

まず、出力ストリームのオープンに失敗した場合、メソッドは実際にはnot awriteをスローします。ソースを参照してください-1532行目。これは、回復コードが実行されない理由を説明しています。IIOExceptionFileNotFoundException

第二に、あなたの回復戦略は少し疑わしいです。これらのファイル ハンドルをすべて使用しているものが 2 秒以内に解放されるという保証はありません。実際、最悪の場合、解放されない可能性もあります。

しかし、最も重要なことは、問題の間違った部分に焦点を合わせていることです。回復メカニズムを考え出すよりも、なぜアプリケーションが非常に多くのファイル記述子を開いているのかという問題に焦点を当てる必要があります。これはリソースリークのようなにおいがします。コードベースに対して FindBugs を実行して、漏れのあるコードを識別できるかどうかを確認することをお勧めします。コードが外部ストリームを開くすべての場所で、ストリームが常に閉じられるようにするためclose()に、ブロック内に一致する呼び出しが必要です。例えばfinally

    OutputStream os = new FileOutputStream(...)
    try {
        // do stuff
    } finally {
        os.close();
    }

また

    // Java 7 form ...
    try (OutputStream os = new FileOutputStream(...)) {
        // do stuff
    }

これを実行しているリソースには 1024 個のファイル ハンドラーしかなく、それを変更することは別の問題です。このプログラムはシミュレーションであり、別の大量の入力データを読み込むと同時に、多数の出力ファイルを書き出します。その作業は、ExecutorService を使用してスレッド化されます。プログラムは、ファイル ハンドラーの制限がより高い別のコンピューターで最後まで実行されますが、ファイル ハンドラーの数が制限されているリソースでプログラムを動作させたいと考えています。

したがって、その数のファイルを開く必要があると言っているようです。

根本的な問題はアプリケーションのアーキテクチャにあると思います。同時に実行するシミュレーション タスクが多すぎるようです。エグゼキューターのスレッド プール サイズを、開いているファイル記述子の最大数よりも数少ないサイズに減らすことをお勧めします。

問題は、現在の戦略がデッドロックの形につながる可能性があることです...新しいタスクの実行が開始されるまで既存のタスクは進行できませんが、既存のタスクがファイル記述子を解放するまで新しいタスクは開始できません。

入力と出力を処理するには別のアプローチが必要だと思います。すべてのアクティブなファイルを同時に開く必要がないように、完全な入力および/または出力ファイルをメモリ (など) にバッファリングするか、ある種のマルチプレクサを実装します。

于 2013-01-22T14:57:40.317 に答える