ファイルディスクリプタ

OS がオープンしたファイルやソケットを識別するための整数値

OS低レベル

ファイルディスクリプタとは

ファイルディスクリプタ (File Descriptor, fd) は、OS がオープンしたファイル、ソケット、パイプを識別するための非負整数値である。Unix の「全てはファイル」の思想に基づき、ネットワーク接続もファイルディスクリプタで管理される。

標準のファイルディスクリプタ

標準のファイルディスクリプタを以下にまとめる。

fd名前用途
0stdin標準入力
1stdout標準出力
2stderr標準エラー出力
3+決まった名前は無く、open などが空いている番号を返すファイル、ソケット等
# リダイレクト
echo "hello" > output.txt    # fd 1 (stdout) をファイルに
command 2> error.log          # fd 2 (stderr) をファイルに
command > out.log 2>&1        # stdout と stderr を同じファイルに

Node.js との関係

Node.js との 関係のコード例を示す。

// Node.js の fs モジュールは内部的にファイルディスクリプタを使用
import { open } from 'fs/promises';

const file = await open('/tmp/data.txt', 'r');
console.log(file.fd); // 3 (ファイルディスクリプタ番号)
await file.close();   // fd を解放

ファイルディスクリプタの枯渇

プロセスが使えるファイルディスクリプタの上限は、soft limit と hard limit の 2 段になっている。実際に効くのは soft limit で、hard limit を超えて引き上げられるのは特権プロセスだけである。既定値は環境差が大きく、Linux ディストリビューションでは soft 1024 が長く定番だったが、systemd の設定や macOS では桁が変わる。上限を語るときは推測せず必ず実測する。

# 上限の確認 (soft と hard は別に見る)
ulimit -Sn
ulimit -Hn

# soft limit の変更 — hard limit までなら一般ユーザーでも上げられる
ulimit -n 65536

シェルで上げた上限は、そのシェルとそこから起動した子プロセスにしか効かない。上限はプロセス生成時に親から受け継がれるため、systemd などが起動する常駐サービスには手元のシェルでの変更が届かない。サービス定義側で指定する。

原因症状対策
ソケットのクローズ忘れEMFILE: too many open files接続を確実にクローズ
DB コネクションリーク新しい接続が作れないコネクションプーリング
ファイルのクローズ忘れファイルが開けないtry-finally で確実にクローズ

Lambda でのファイルディスクリプタ

Lambda の実行環境にもファイルディスクリプタの上限がある。2026 年 8 月時点の公開クォータでは 1,024 で、Lambda Managed Instances のみ 4,096 と別枠になっている。大量の同時接続 (HTTP リクエスト、DB コネクション) を開くと枯渇する。

Lambda では実行環境が再利用される点も効いてくる。ハンドラの外で開いた接続は次の呼び出しにも残るので、呼び出しごとに開いて閉じ忘れると、1 回のリクエストでは無事でも同じ環境の数百回目で EMFILE に落ちる。再現しないエラーの典型がこれである。

lsof でファイルディスクリプタを確認

lsof でファイルディスクリプタを確認の例を示す。

# プロセスが開いているファイルディスクリプタを表示
lsof -p <PID>

# そのプロセスのソケットだけに絞る — -a が必須
lsof -a -i -p <PID>

lsof の選択オプションは既定で OR で結合される。-a を付けずに lsof -i -p <PID> と書くと、「全プロセスのソケット」と「そのプロセスが開いている全ファイル」の和集合が出てしまい、絞り込みになっていない。

epoll / kqueue

Node.js の libuv は、大量のファイルディスクリプタを効率的に監視するために epoll (Linux) / kqueue (macOS) を使用する。イベントループの基盤技術である。

ただし、この仕組みが担うのはネットワーク I/O である。libuv はネットワーク I/O をイベントループのスレッドだけで処理する一方、通常ファイルの非同期 I/O はスレッドプールに逃がしている。ファイルディスクリプタという同じ言葉で括られていても、詰まったときに疑う場所は別で、ファイル操作が遅いときはイベントループよりスレッドプールの数 (UV_THREADPOOL_SIZE) を先に見る。

ファイルディスクリプタの理解を深めるには関連書籍が参考になる。

この記事は役に立ちましたか?

関連用語

関連する記事