Claude Codeを日常的に使っていると、気づかないうちにシステムリソースが圧迫されていることがある。本記事では、実際に遭遇した「孤児プロセス」問題の調査結果と対処法を共有する。
発見の経緯
きっかけ
日常業務でClaude Codeを複数のターミナルで使用していたところ、ふと「現在起動しているClaudeはどれだけあるか」と確認したことが発端だった。
確認コマンド
ps aux | grep -i claude | grep -v grep
驚きの結果
user 51459 1.2 3.9 75117368 311800 ? Sl Jan19 17:25 claude --resume
user 68508 1.0 3.7 75869720 291220 ? Sl Jan19 14:12 claude --resume
user 321852 103 10.3 75371668 816196 pts/11 Rl+ 09:16 1:40 claude --resume
user 322159 34.1 6.4 74698316 507716 pts/12 Rl+ 09:17 0:06 claude
user 3635391 1.2 39.2 93552724 3082900 pts/8 Sl+ Jan14 98:00 claude
user 3725562 0.4 2.4 75583064 193532 ? Sl Jan15 31:49 claude --resume
6つのClaudeプロセスが起動しており、合計で約5GBのメモリを消費していた。
問題の状況分析
プロセスの分類
詳細を調査すると、プロセスは2種類に分類できた。
ps -eo pid,ppid,stat,tty,cmd | grep -i claude | grep -v grep
| PID | PPID | TTY | 状態 | 分類 |
|---|---|---|---|---|
| 51459 | 1 | ? | Sl | 孤児プロセス |
| 68508 | 1 | ? | Sl | 孤児プロセス |
| 3725562 | 1 | ? | Sl | 孤児プロセス |
| 321852 | 316963 | pts/11 | Sl+ | 正常(アクティブ) |
| 322159 | 316964 | pts/12 | Rl+ | 正常(現在のセッション) |
| 3635391 | 1262863 | pts/8 | Sl+ | 正常(長時間稼働) |
PPID=1 は、親プロセス(ターミナル)が終了した後、initプロセス(systemd)に引き取られたことを意味する。TTY=? は、制御端末が存在しないことを示す。
リソース消費の内訳
| プロセス | 起動日 | メモリ | 状態 |
|---|---|---|---|
| PID 3635391 | 1月14日 | 3.0GB | 6日以上稼働 |
| PID 321852 | 本日 | 816MB | アクティブ |
| PID 322159 | 本日 | 508MB | 現在使用中 |
| PID 51459 | 1月19日 | 312MB | 孤児 |
| PID 68508 | 1月19日 | 291MB | 孤児 |
| PID 3725562 | 1月15日 | 194MB | 孤児 |
システムは42日間稼働しており、その間にプロセスが蓄積していた。
技術的調査
ファイルディスクリプタの確認
孤児プロセスのファイルディスクリプタを調査した。
ls -la /proc/51459/fd
lrwx------ 1 user user 64 Jan 20 09:19 0 -> /dev/pts/20 (deleted)
lrwx------ 1 user user 64 Jan 20 09:19 1 -> /dev/pts/20 (deleted)
lrwx------ 1 user user 64 Jan 20 09:19 2 -> /dev/pts/20 (deleted)
stdin/stdout/stderrがすべて (deleted) となっている。これは、ターミナル(pts/20)が閉じられた後もプロセスが終了せずに残っていることを示す。
シグナルマスクの解析
プロセスがどのシグナルを処理しているか確認した。
cat /proc/51459/status | grep -E "^(SigIgn|SigCgt)"
SigIgn: 0000000000001000
SigCgt: 00000001280004c8
これをデコードすると:
| 種別 | シグナル |
|---|---|
| 無視 | SIGPIPE (13) |
| キャッチ | SIGILL, SIGBUS, SIGFPE, SIGSEGV, SIGWINCH, SIGPWR |
| 未処理 | SIGHUP (1), SIGINT, SIGTERM など |
SIGHUP(ターミナル切断シグナル)が未処理であることがわかった。通常、SIGHUPを受信するとプロセスは終了するが、何らかの理由でシグナルが配信されていない。
セッション情報の確認
cat /proc/51459/stat | awk '{print "Session ID:", $6, "Process Group:", $5}'
Session ID: 51175 Process Group: 51459
プロセスは独自のプロセスグループリーダーになっており、元のセッション(51175)はすでに存在しない。この状態ではSIGHUPが配信されない可能性がある。
原因の考察
なぜプロセスが終了しないのか
- ターミナルの閉じ方: ターミナルウィンドウを直接閉じると、SIGHUPの配信タイミングによってはプロセスが終了しない場合がある
- プロセスグループの分離: Claude Codeが独自のプロセスグループを作成しているため、親シェルからのシグナルが届かない
- ネイティブ実行ファイルの問題: Claude CodeはELF形式のネイティブ実行ファイルだが、内部的なシグナル処理に問題がある可能性
既知の問題(コミュニティ報告)
GitHubで複数の関連イシューが報告されている。
MCPサーバーの孤児プロセス
Claude Code does not properly clean up MCP server processes when exiting, leading to orphaned processes that continue consuming system resources indefinitely.
プロセス終了の未処理
メンテナーからの回答:
We’re shifting towards a native executable that does not run via node entry point, which should prevent this sort of issue.
プロセスグループの問題
The issue appears to be that Claude Code and its spawned background processes share the same process group. When Claude sends a signal to kill the process group, it kills itself too.
対処法
即時クリーンアップ
Linux環境の場合:
# TTYが「?」の孤児プロセスを検出して終了
ps aux | grep '[c]laude' | awk '$7 == "?" {print $2}' | xargs kill -9 2>/dev/null
確認コマンド:
# 孤児プロセスの数を確認
ps aux | grep '[c]laude' | awk '$7 == "?" {print $2}' | wc -l
# 全Claudeプロセスの一覧
ps aux | grep '[c]laude' | awk '{printf "PID: %s, TTY: %s, MEM: %s MB\n", $2, $7, $6/1024}'
定期クリーンアップの設定
crontabに追加(1時間ごと):
crontab -e
# 以下を追加
0 * * * * ps aux | grep '[c]laude' | awk '$7 == "?" {print $2}' | xargs kill -9 2>/dev/null
systemd timerを使用する場合:
~/.config/systemd/user/claude-cleanup.service:
[Unit]
Description=Cleanup orphaned Claude processes
[Service]
Type=oneshot
ExecStart=/bin/bash -c "ps aux | grep '[c]laude' | awk '$7 == \"?\" {print $2}' | xargs kill -9 2>/dev/null || true"
~/.config/systemd/user/claude-cleanup.timer:
[Unit]
Description=Run Claude cleanup hourly
[Timer]
OnCalendar=hourly
Persistent=true
[Install]
WantedBy=timers.target
有効化:
systemctl --user enable --now claude-cleanup.timer
予防策
1. 正しい終了方法を習慣化
/exitコマンドを使用Ctrl+Cで中断- ターミナルを閉じる前にClaudeが終了していることを確認
2. シェルのexit時にクリーンアップ
.bashrc または .zshrc に追加:
trap 'pkill -9 -P $$ claude 2>/dev/null' EXIT
3. 便利なエイリアスの設定
alias claude-cleanup='ps aux | grep "[c]laude" | awk "\$7 == \"?\" {print \$2}" | xargs kill -9 2>/dev/null; echo "Cleanup complete"'
alias claude-status='ps aux | grep "[c]laude" | awk "{printf \"PID: %s, TTY: %s, MEM: %.0f MB, TIME: %s\\n\", \$2, \$7, \$6/1024, \$10}"'
まとめ
| 項目 | 内容 |
|---|---|
| 問題 | Claude Codeのプロセスがターミナル終了後も残り続ける |
| 影響 | メモリリーク(本環境では5GB消費) |
| 原因 | シグナルハンドリングとプロセスグループ管理の問題 |
| ステータス | 既知のバグとしてGitHubで報告済み |
| 公式対応 | ネイティブ実行ファイルへの移行で対応予定 |
| ユーザー対応 | 定期クリーンアップスクリプトの導入 |
Claude Codeは強力なツールだが、長時間使用する環境では孤児プロセスの蓄積に注意が必要である。開発元は問題を認識しており、将来のバージョンで根本的な修正が行われる予定だ。それまでは、本記事で紹介したクリーンアップ手法を活用してリソースを管理することを推奨する。
調査環境:
– OS: Linux (RHEL系) 5.14.0
– Claude Code: v2.1.12
– システム稼働時間: 42日


コメント