Перехват и обработка исключения в Java с сообщением (слишком много открытых файлов)

У меня возникла проблема, аналогичная (слишком много дескрипторов открытых файлов), когда я попробуйте запустить программу на грид-компьютере. Недоступна опция увеличения лимита операционной системы на общее количество открытых файлов на этом ресурсе.

Я пытался поймать и обработать исключение, но, похоже, исключения не происходит. Исключение, кажется, сообщает о себе как FileNotFoundException. Одно из мест, где генерируется исключение, находится в методе, показанном ниже:

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)

У меня есть несколько идей по решению этой проблемы, но кто-нибудь знает, что не так?

(Я пытался опубликовать версию этого вопроса в качестве ответа на этот вопрос, но это было удалено модератором)


person Andy Turner    schedule 22.01.2013    source источник
comment
Если ваше предложение try не перехватывает исключение, это может быть связано с тем, что вы ссылаетесь на неправильный класс. Вы точно ловите FileNotFoundException от java.io?   -  person Duncan Jones    schedule 22.01.2013
comment
Спасибо Дункан. Я подозревал, что должен поймать другое исключение. Я думаю, что могу проверить, какое исключение заставило программу задохнуться, поэтому я должен сделать это и отчитаться. Стивен предположил, что я должен перехватывать javax.imageio.IIOException, поэтому я пытаюсь это сделать. Еще раз спасибо за ваше предложение.   -  person Andy Turner    schedule 22.01.2013
comment
Кстати, я поймал java.io.FileNotFoundException, спасибо @DuncanJones   -  person Andy Turner    schedule 28.01.2013


Ответы (1)


Во-первых, метод write на самом деле выдаст IIOException, а не FileNotFoundException, если ему не удастся открыть выходной поток; см. источник — строка 1532. Это объясняет, почему ваш код восстановления никогда не запускается.

Во-вторых, ваша стратегия восстановления немного сомнительна. У вас нет гарантии, что то, что использует все эти дескрипторы файлов, освободит их через 2 секунды. Ведь в худшем случае они могут никогда не выйти на свободу.

Но самое главное, что вы фокусируетесь не на той части проблемы. Вместо того, чтобы пытаться придумать механизм восстановления, вы должны сосредоточиться на проблеме, почему приложение имеет так много открытых файловых дескрипторов. Это попахивает утечкой ресурсов. Я рекомендую вам запустить FindBugs в вашей кодовой базе, чтобы увидеть, сможет ли он идентифицировать негерметичный код. Везде, где ваш код открывает внешний поток, он должен иметь соответствующий вызов close() в блоке finally, чтобы гарантировать, что поток всегда закрыт; например

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

or

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

Ресурс, на котором я это запускаю, имеет только 1024 обработчика файлов, и изменить это — еще одна проблема. Программа является симуляцией, и она записывает большое количество выходных файлов одновременно с чтением другой партии входных данных. Эта работа выполняется с помощью ExecutorService. Программа выполняется до конца на другом компьютере с более высоким лимитом обработчиков файлов, но я хочу, чтобы она работала на ресурсе, где я ограничен меньшим количеством обработчиков файлов.

Итак, похоже, вы говорите, что вам нужно открыть такое количество файлов.

Мне кажется, что корень проблемы в архитектуре вашего приложения. Похоже, у вас просто слишком много задач моделирования одновременно. Я предлагаю вам уменьшить размер пула потоков исполнителя на несколько меньше, чем максимальное количество дескрипторов открытых файлов.

Проблема в том, что ваша текущая стратегия может привести к тупиковой ситуации... когда существующие задачи не могут выполняться до тех пор, пока не начнут выполняться новые задачи, а новые задачи не могут начаться до тех пор, пока не будут выпущены существующие задачи. файловые дескрипторы.

Я думаю, вам нужен другой подход к обработке ввода и вывода. Либо буферизуйте полные входные и/или выходные файлы в памяти (и так далее), либо реализуйте какой-либо мультиплексор, чтобы не нужно было открывать все активные файлы одновременно.

person Stephen C    schedule 22.01.2013
comment
Спасибо, это полезно. Я попытаюсь поймать IIOException и посмотреть, работает ли моя обработка. Ресурс, на котором я это запускаю, имеет только 1024 обработчика файлов, и изменить это — еще одна проблема. Программа является симуляцией, и она записывает большое количество выходных файлов одновременно с чтением другой партии входных данных. Эта работа выполняется с помощью ExecutorService. Программа выполняется до конца на другом компьютере с более высоким лимитом обработчиков файлов, но я хочу, чтобы она работала на ресурсе, где я ограничен меньшим количеством обработчиков файлов. Спасибо еще раз. - person Andy Turner; 22.01.2013
comment
P.S. Я уверен, что закрываю открытые потоки правильно, но спасибо, что указали мне на FindBugs (findbugs.sourceforge.net ) выглядит как полезный ресурс. - person Andy Turner; 22.01.2013
comment
@StephenC Как вы объясните FileNotFoundException в трассировке стека? - person Duncan Jones; 22.01.2013
comment
@DuncanJones - либо он использует другую версию Java (которая не перехватывает IOException и не оборачивает его), либо он показал нам только частичную трассировку стека. Подозреваю последнее. - person Stephen C; 23.01.2013
comment
Помимо перехвата FileNotFoundException, я также пытался перехватывать IIOException и использовать ту же обработку. Я планирую снова попытаться поймать общее исключение IOException и выполнить ту же обработку, но я ожидаю, что это тоже не удастся. Вскоре я подтвержу версии Java и предоставлю ссылки на полную трассировку стека. - person Andy Turner; 23.01.2013
comment
В момент сбоя программа моделирования, вероятно, одновременно записывает тысячи выходных файлов. Он также может пытаться прочитать входной файл, используемый на следующем этапе симуляции, или он может завершить это и продолжить. Он не завершит этот этап моделирования и будет записывать дальнейшие выходные данные. Я могу написать дополнительные диагностические данные, чтобы лучше понять, что происходит в момент сбоя. - person Andy Turner; 23.01.2013
comment
Никакие файлы, записанные как выходные данные с помощью ExecutorService, не открываются снова для чтения. Тем не менее, может быть потенциал взаимоблокировки, так как моделирование интенсивно использует память и обменивает данные между памятью и файловыми хранилищами в реализации, требующей обработчиков файлов для этого обмена. Ограничение пула ExecutorService — хорошая идея, которую я попробую дальше. Еще раз спасибо за вашу помощь и отзывы по этому поводу. - person Andy Turner; 23.01.2013
comment
Я разместил полную трассировку стека из последнего запуска в Интернете: geog.leeds.ac.uk/people/a.turner/personal/blog/archive/2013/01/ - person Andy Turner; 23.01.2013
comment
Там сообщается о различных ошибках и исключениях. Извини за это. Возможно, именно исключение NullPointerException заставляет программу возвращаться с ошибкой. - person Andy Turner; 23.01.2013
comment
@Stephen C Информация о версии Java: версия java 1.6.0_37 Java(TM) SE Runtime Environment (сборка 1.6.0_37-b06) Java HotSpot(TM) 64-битная виртуальная машина сервера (сборка 20.12-b01, смешанный режим) - person Andy Turner; 23.01.2013
comment
Моделирование записывает 154 набора выходных данных. Для каждого набора есть 23 изображения и 28 других типов файлов. Итак, всего это 7854 файла. Хотя нет необходимости открывать все эти файлы для записи, записывать их один за другим может быть медленно, но опять же, сейчас это возможно. Возможно, это было одной из вещей, к которым стремился @StephenC. В любом случае, я отказываюсь от создания выходных изображений, так как нет надежного способа создать BufferredImage с многопоточностью в ресурсе Grid Computing, который я использую. Я должен избегать многопоточности. Так что будем писать другие файлы последовательно... - person Andy Turner; 24.01.2013
comment
... Итак, фактически я убегаю от этого, не зная, в чем проблема или ответ. Еще раз спасибо всем, кто пытался помочь. Надеюсь, то, что здесь осталось, кому-то пригодится. Я постараюсь сохранить эту полную трассировку стека онлайн. - person Andy Turner; 24.01.2013