уменьшить количество открытых файлов в коде Java

#java #io #java-io

#java #io #java-ввод-вывод

Вопрос:

Привет, у меня есть некоторый код, который использует блок

 RandomAccessFile file = new RandomAccessFile("some file", "rw");
FileChannel channel = file.getChannel();

// some code
String line = "some data";
ByteBuffer buf = ByteBuffer.wrap(line.getBytes());
channel.write(buf);

channel.close();
file.close();
  

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

Проблема в том, что иногда я перехватываю исключение

 Failed with exception Too many open files
  

во время запуска приложения.

Я хотел бы знать, есть ли какой-либо способ сообщить ОС, что файл уже закрыт и больше не используется, почему

 channel.close();
file.close();
  

не уменьшает количество открытых файлов. Есть ли какой-либо способ сделать это в коде Java?

Я уже увеличил максимальное количество открытых файлов в

 #/etc/sysctl.conf:
kern.maxfiles=204800
kern.maxfilesperproc=200000
kern.ipc.somaxconn=8096
  

Обновить:
Я пытался устранить проблему, поэтому я разделил код, чтобы исследовать каждую его часть (создавать файлы, загружать в hive, удалять файлы).

Использование класса ‘File’ или ‘RandomAccessFile’ завершается ошибкой, за исключением «Слишком много открытых файлов».

Наконец, я использовал код:

 FileOutputStream s = null;
FileChannel c = null;

try {
    s = new FileOutputStream(filePath);
    c = s.getChannel();
    // do writes
    c.write("some data"); 
    c.force(true);
    s.getFD().sync();

} catch (IOException e) {
    // handle exception
} finally {
    if (c != null)
        c.close();
    if (s != null)
        s.close();
}
  

И это работает с большими объемами файлов (протестировано на 20 КБ с размером 5 КБ каждый). Сам код не генерирует исключение, как предыдущие два класса.
Но в производственном коде (с hive) все еще было исключение. И похоже, что причиной этого является подключение к hive через JDBC.
Я продолжу расследование.

Комментарии:

1. Похоже, что что-то зависит от финализатора для закрытия внешних ресурсов. Это … на самом деле напрашивается на неприятности.

Ответ №1:

Количество дескрипторов открытых файлов, которые могут использоваться операционной системой, — это не то же самое, что количество дескрипторов файлов, которые могут быть открыты процессом. Большинство систем Unix ограничивают количество дескрипторов файлов на процесс. Скорее всего, это что-то вроде 1024 файловых дескрипторов для вашей JVM.

a) Вам нужно установить ulimit в оболочке, которая запускает JVM, на некоторое более высокое значение. (Что-то вроде ‘ulimit -n 4000’)

б) Вы должны убедиться, что у вас нет утечек ресурсов, которые препятствуют «доработке» ваших файлов.

Ответ №2:

Обязательно используйте блок finally{}. Если по какой-либо причине возникает исключение, закрытие никогда не произойдет в написанном коде.

Ответ №3:

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

Комментарии:

1. схема использования следующая: 1) получить данные из источника mysql в некоторые объекты данных 2) зациклить список объектов и на каждой итерации выполнять опубликованный код. Итак, я выполняю опубликованный фрагмент кода на каждой итерации и не открываю все файлы один раз.