Устранение неполадок «Открыто слишком много файлов» с помощью lsof

У меня есть приложение Java, работающее в Linux с PID 25426. При запуске lsof -p 25426 я заметил:

java    25426 uid  420w  FIFO                0,8      0t0 273664482 pipe
java    25426 uid  421r  FIFO                0,8      0t0 273664483 pipe
java    25426 uid  461r  FIFO                0,8      0t0 273622888 pipe
java    25426 uid  463w  FIFO                0,8      0t0 273633139 pipe
java    25426 uid  464r  FIFO                0,8      0t0 273633140 pipe
java    25426 uid  465r  FIFO                0,8      0t0 273622889 pipe
java    25426 uid  471w  FIFO                0,8      0t0 273623682 pipe
java    25426 uid  472r  FIFO                0,8      0t0 273633141 pipe

Как следует интерпретировать этот результат?

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

По мере того, как приложение продолжает работать, количество pipe записей меняется (увеличивается и уменьшается).


person James Raitsev    schedule 11.04.2013    source источник


Ответы (1)


Определение

  • java — процесс с открытым файлом.
  • 25426 — это должен быть настоящий PID. Если нет, сообщите нам, что это такое, разместив заголовок.
  • 420 w – номер дескриптора файла, за которым следует режим, в котором он был открыт. (Читай пиши)
  • 0,8 – основная идентификация второстепенного устройства.
  • 273664482 — индекс файла.
  • канал – канал FIFO, открытый в вашем приложении.

Интерпретация

Вы не закрываете все свои потоки. Есть много дескрипторов открытых файлов в режиме чтения или записи, которые записываются в безымянные каналы. Чаще всего это происходит, когда люди используют Runtime.getRuntime.exec(), а затем сохраните потоки, связанные с процессом, открытыми. Вы можете использовать общую библиотеку утилит ввода-вывода для закройте их или вы можете закрыть их самостоятельно< /а>.

    try
    {
        p = Runtime.getRuntime().exec("something");
    }
    finally
    {
        if (p != null)
        {
            IOUtils.closeQuietly(p.getOutputStream());
            IOUtils.closeQuietly(p.getInputStream());
            IOUtils.closeQuietly(p.getErrorStream());
        }
    }

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

person Deepak Bala    schedule 11.04.2013
comment
Спасибо за чудесно подробный ответ. Я делаю что-то подобное в своем коде process = Runtime.getRuntime().exec(commandLineAsString);, но позже finally { if (process != null) { process.destroy(); } }. Является ли pipe результатом этой попытки выполнения? Пожалуйста, обратите внимание, что количество каналов продолжает увеличиваться и уменьшаться. - person James Raitsev; 11.04.2013
comment
destroy() — это нативный метод, поэтому никто не может сказать, что он делает в реализациях ОС. Возможно, в вашем случае вам повезло, что завершенный процесс пытается очистить свои незавершенные FD (я размышляю, чтобы попытаться объяснить разницу в количестве каналов). Контракт метода destroy() не требует закрытия потоков. - person Deepak Bala; 11.04.2013
comment
Кроме приведенного выше примера, что еще заставит lsof сообщить о pipe, пожалуйста? - person James Raitsev; 12.04.2013