#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) зациклить список объектов и на каждой итерации выполнять опубликованный код. Итак, я выполняю опубликованный фрагмент кода на каждой итерации и не открываю все файлы один раз.