IOException: слишком много открытых файлов - PullRequest
26 голосов
/ 11 января 2010

Я пытаюсь отладить утечку файлового дескриптора в веб-приложении Java, работающем в Jetty 7.0.1 в Linux.

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

java.io.IOException: Cannot run program [external program]: java.io.IOException: error=24, Too many open files
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:459)
    at java.lang.Runtime.exec(Runtime.java:593)
    at org.apache.commons.exec.launcher.Java13CommandLauncher.exec(Java13CommandLauncher.java:58)
    at org.apache.commons.exec.DefaultExecutor.launch(DefaultExecutor.java:246)

Сначала я подумал, что проблема в коде, который запускает внешнюю программу, но он использует commons-exec , и я не вижу в этом ничего плохого:

CommandLine command = new CommandLine("/path/to/command")
    .addArgument("...");
ByteArrayOutputStream errorBuffer = new ByteArrayOutputStream();
Executor executor = new DefaultExecutor();
executor.setWatchdog(new ExecuteWatchdog(PROCESS_TIMEOUT));
executor.setStreamHandler(new PumpStreamHandler(null, errorBuffer));
try {
    executor.execute(command);
} catch (ExecuteException executeException) {
    if (executeException.getExitValue() == EXIT_CODE_TIMEOUT) {
        throw new MyCommandException("timeout");
    } else {
        throw new MyCommandException(errorBuffer.toString("UTF-8"));
    }
}

Список открытых файлов на сервере. Я вижу большое количество FIFO:

# lsof -u jetty
...
java    524 jetty  218w  FIFO        0,6      0t0 19404236 pipe
java    524 jetty  219r  FIFO        0,6      0t0 19404008 pipe
java    524 jetty  220r  FIFO        0,6      0t0 19404237 pipe
java    524 jetty  222r  FIFO        0,6      0t0 19404238 pipe

когда начинается Причал, остается всего 10 FIFO, а через несколько дней их сотни.

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

Ответы [ 7 ]

24 голосов
/ 11 мая 2011

Проблема связана с вашим Java-приложением (или используемой вами библиотекой).

Сначала , вы должны прочитать все выходные данные (Google для StreamGobbler) и быстро!

Javadoc говорит:

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

Во-вторых , waitFor() Ваш процесс прерван. Затем вы должны закрыть потоки ввода, вывода и ошибок.

Наконец destroy() ваш процесс.

Мои источники:

8 голосов
/ 11 января 2010

Поскольку вы работаете в Linux, я подозреваю, что у вас заканчиваются файловые дескрипторы. Проверьте ulimit. Вот статья, которая описывает проблему: http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

7 голосов
/ 11 января 2010

Ваша внешняя программа не работает должным образом. Посмотрите, почему он этого не делает.

5 голосов
/ 31 июля 2014

Помимо рассмотрения основных причин, таких как утечка файлов и т. Д., Для законного увеличения лимита «открытых файлов» и его сохранения при перезагрузках рассмотрите возможность редактирования

/etc/security/limits.conf

добавив что-то вроде этого

jetty soft nofile 2048
jetty hard nofile 4096

где "jetty" - это имя пользователя в этом случае. Для получения более подробной информации о limit.conf см. http://linux.die.net/man/5/limits.conf

выйдите из системы, а затем снова войдите в систему и выполните команду

ulimit -n

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

Ограничение по умолчанию 1024 может быть слишком низким для больших приложений Java.

5 голосов
/ 11 января 2010

Не знаю природу вашего приложения, но я видел, как эта ошибка проявлялась несколько раз из-за утечки пула соединений, так что стоило бы проверить. В Linux сокет-соединения используют как файловые дескрипторы, так и файлы файловой системы. Просто мысль.

2 голосов
/ 24 марта 2011

Вы можете справиться с FDS самостоятельно. Exec в Java возвращает объект процесса. Периодически проверяйте, запущен ли процесс. После завершения закройте потоки процессов STDERR, STDIN и STDOUT (например, proc.getErrorStream.close ()). Это уменьшит утечки.

0 голосов
/ 06 июня 2018

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

https://www.tecmint.com/increase-set-open-file-limits-in-linux/

Как изменить ограничение на количество открытых файлов в Linux?

...