На Linux и других UNIX / UNIX-подобных платформах ОС накладывает ограничение на количество дескрипторов открытых файлов, которые процесс может иметь в любой момент времени. В старые времена этот предел был жестким 1 и относительно небольшим. В наши дни он намного больше (сотни / тысячи) и подчиняется «мягкому» настраиваемому ограничению ресурсов для каждого процесса. (Посмотрите встроенную оболочку ulimit
...)
Ваше Java-приложение должно превышать лимит дескриптора файла для процесса.
Вы говорите, что у вас открыто 19 файлов, и через несколько сотен раз вы получаете IOException, говорящее «слишком много файлов открыто». Теперь это конкретное исключение может произойти ТОЛЬКО при запросе нового файлового дескриптора; то есть когда вы открываете файл (или канал или сокет). Вы можете проверить , напечатав трассировку стека для IOException.
Если ваше приложение не запускается с небольшим ограничением ресурсов (что кажется маловероятным), из этого следует, что оно должно многократно открывать файлы / сокеты / каналы и не закрывать их. Узнайте, почему это происходит, и вы сможете понять, что с этим делать.
К вашему сведению, следующий шаблон является безопасным способом записи в файлы, который гарантированно не пропускает файловые дескрипторы.
Writer w = new FileWriter(...);
try {
// write stuff to the file
} finally {
try {
w.close();
} catch (IOException ex) {
// Log error writing file and bail out.
}
}
1 - Зашито, как скомпилировано в ядро. Изменение количества доступных слотов fd потребовало перекомпиляции ... и может привести к уменьшению объема памяти, доступной для других целей. В те дни, когда Unix обычно работал на 16-битных машинах, эти вещи действительно имели значение.
UPDATE
Способ Java 7 более лаконичен:
try (Writer w = new FileWriter(...)) {
// write stuff to the file
} // the `w` resource is automatically closed
ОБНОВЛЕНИЕ 2
Очевидно, вы также можете столкнуться с «слишком большим количеством открытых файлов» при попытке запуска внешней программы. Основная причина, как описано выше. Однако причина, по которой вы сталкиваетесь с этим в exec(...)
, заключается в том, что JVM пытается создать дескрипторы файлов «pipe», которые будут подключены к стандартному вводу / выводу / ошибке внешнего приложения.