Что такое файловый дескриптор?
- Что означает ошибка Too many open files?
- Почему в Unix «всё есть файл»?
- Что такое stdin, stdout и stderr?
Файловый дескриптор — небольшое целое число, по которому процесс обращается к открытому ресурсу: файлу, сокету, каналу, устройству.
- 0, 1, 2 — stdin, stdout, stderr
- Лимит на процесс (ulimit -n, часто 1024) — при утечке «Too many open files»
- Сокеты тоже дескрипторы: каждое соединение тратит один
А ещё Закрывать ресурсы: try-with-resources, with, defer
Подробно
Когда процесс открывает файл (open), ядро создаёт запись об открытом ресурсе и возвращает процессу индекс в его таблице — файловый дескриптор. Дальше все операции идут по номеру: read(fd, ...), write(fd, ...), close(fd).
«Всё есть файл». Через тот же интерфейс в Unix работают сокеты, каналы (| в shell), терминалы, устройства, таймеры (timerfd), события (eventfd). Поэтому одним epoll можно ждать готовности и сетевых соединений, и каналов, а перенаправление > в shell просто подменяет дескриптор 1.
Стандартные: 0 — stdin, 1 — stdout, 2 — stderr. 2>&1 — направить stderr туда же, куда stdout.
Лимиты. На процесс есть ограничение числа открытых дескрипторов — ulimit -n, по умолчанию часто 1024 (мягкий лимит). Для сервера с десятками тысяч соединений его поднимают (LimitNOFILE в systemd, nofile в limits.conf). Есть и общесистемный fs.file-max.
Too many open files (EMFILE) — обычно не «мало лимита», а утечка: файлы, сокеты или HTTP-соединения открываются и не закрываются. Ищут через ls /proc/<pid>/fd | wc -l и lsof -p <pid> — видно, чего накопилось. Лечение — закрывать ресурсы гарантированно: try-with-resources в Java, with в Python, defer в Go; переиспользовать HTTP-клиент с пулом вместо нового клиента на каждый запрос.
Наследование. После fork дочерний процесс получает копии дескрипторов; чтобы не утекали в запускаемые программы, их открывают с флагом O_CLOEXEC. Удалённый, но открытый файл продолжает занимать место на диске, пока дескриптор не закрыт — классическая загадка «диск полон, а файлов нет» с лог-файлом, который удалили у работающего процесса.
Пример
$ ulimit -n
1024
$ ls /proc/$(pgrep -f app.jar)/fd | wc -l
1019
$ lsof -p $(pgrep -f app.jar) | awk '{print $5}' | sort | uniq -c
12 REG
987 IPv4 # сокеты не закрываются — утечка соединенийЧто хотят услышать
- Дескриптор — номер открытого ресурса в таблице процесса.
- Сокеты и каналы — тоже дескрипторы.
- 0, 1, 2 и перенаправление.
- Too many open files: лимит, утечки, диагностика через /proc и lsof.
Частые ошибки
- Просто поднимать лимит, не поискав утечку.
- Думать, что удалённый файл сразу освобождает место.
Проверьте себя
Один верный вариант. Подумайте, потом откройте ответ.
Показать варианты и ответ
- ✗Полный путь к файлу на диске, по которому процесс каждый раз заново открывает файл при чтении или записи
- ✗Номер процесса, открывшего файл, в таблице процессов
- ✗Сокеты не используют дескрипторы, только файлы на диске
- ✓Целое число, по которому процесс обращается к открытому ресурсу
Что спросят дальше
Связанные вопросы
Разбор собеседования с sotto
После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.