Linux: プロセス管理 — ps / top / killとシステム監視
Linuxでは、実行中のプログラムをプロセスと呼びます。プロセスの管理 — 何が動いているか、リソースをどれだけ使っているか、どう安全に停止するか — はサーバー管理のコアスキルです。
📋 前提条件:まず以下を完了していること
- レッスン3:ターミナルの基礎
1. このレッスンで学ぶこと
- ps:プロセス一覧の確認
- top/htop:リアルタイム監視
- kill vs kill -9
- バックグラウンド実行(& / nohup / disown)
- niceによるプロセス優先度調整
2. サービスが起動しないストーリー
(1) 悩み:ポートが既に使用中
小明はNode.jsサービスを起動しようとして次のエラーに遭遇しました:
node server.js
# Error: listen EADDRINUSE: address already in use :::3000
ポートが占有されていました。どのプロセスがポート3000を使っているのか、どう停止すればいいのか分かりませんでした。
(2) ポートを特定して解放
# Find the process using port 3000
ss -tlnp | grep 3000
# LISTEN 0 128 *:3000 *:* users:(("node",pid=1234,fd=20))
# Terminate the process
kill 1234
# Restart the service
node server.js
(3) 得られるもの:ポート競合の解決
小明はssやlsofでポートを占有するプロセスを見つけ、killでシグナルを送って終了する方法を学びました。今では30秒でポート競合を解決できます。
3. 知識ポイント
(1) ps — プロセススナップショット
# Core usage
ps aux # Detailed info on all processes
ps aux | grep nginx # Filter specific processes
ps -ef # Standard format
# Common field meanings
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
# alice 1234 0.3 1.2 123456 54321 ? Ssl 10:23 0:01 node server.js
# Custom output
ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -10
| フィールド | 意味 |
|---|---|
| PID | プロセスID |
| PPID | 親プロセスID |
| %CPU | CPU使用率 |
| %MEM | メモリ使用率 |
| VSZ | 仮想メモリサイズ(KB) |
| RSS | 物理メモリサイズ(KB) |
| STAT | プロセス状態(R=実行中、S=待機、D=割り込み不可、Z=ゾンビ、T=停止) |
| START | 開始時刻 |
| TIME | 累積CPU時間 |
| COMMAND | コマンド名 / コマンドライン |
(2) top/htop — リアルタイム監視
top # Start top
top -o %MEM # Sort by memory
top -u alice # Show only specific user processes
top -bn1 | head -20 # One-shot output
# Hotkeys while top is running
# P Sort by CPU
# M Sort by memory
# k Kill process (prompts for PID)
# u Filter by user
# q Quit top
# htop is an enhanced version of top (nicer UI, mouse support)
htop
(3) kill — シグナルの送信
kill PID # Send SIGTERM (15), request termination
kill -2 PID # Send SIGINT (2), equivalent to Ctrl+C
kill -9 PID # Send SIGKILL (9), force termination
kill -1 PID # Send SIGHUP (1), reload config
kill -19 PID # Send SIGSTOP (19), pause process
kill -18 PID # Send SIGCONT (18), resume process
# Kill by name
pkill -f "node server.js" # Match command line
killall nginx # Kill all processes with the same name
| シグナル | 番号 | 意味 |
|---|---|---|
| SIGHUP | 1 | ハングアップ(設定再読み込み) |
| SIGINT | 2 | 割り込み(Ctrl+C) |
| SIGQUIT | 3 | 終了(コアダンプ付き) |
| SIGKILL | 9 | 強制終了(捕捉/無視不可) |
| SIGTERM | 15 | 終了要求(デフォルト) |
| SIGSTOP | 19 | 停止(捕捉/無視不可) |
| SIGCONT | 18 | 実行再開 |
核心原則: まず
kill PID(SIGTERM)を試す。それでも終了しない場合のみkill -9 PID(SIGKILL)を使用。SIGKILLはプロセスにクリーンアップの機会を与えず、データ損失の原因になる可能性があります。
kill -9(SIGKILL)はプロセスを強制終了し、クリーンアップの機会がありません — 開いているファイルが破損、データベーストランザクションが中断、一時ファイルが残留する可能性があります。kill PID(SIGTERM)が応答しない場合のみ-9を使用してください。ショートカットとして使わないこと。
(4) バックグラウンド実行
# & — Put in background
node server.js & # Returns terminal immediately after starting
> 💡 ヒント:コマンドの末尾に`&`を付けるとバックグラウンドで実行され、ターミナルがすぐに解放されます。ただし、`&`だけではターミナルセッション終了時にプロセスも終了します。ターミナルを閉じてもプロセスを継続させるには、`nohup`と組み合わせます:`nohup command &`。
sleep 30 & # Run sleep in background
# jobs/fg/bg — Manage background jobs
jobs # List background jobs
# [1]+ Running node server.js &
# [2]- Running sleep 30 &
fg %1 # Bring job 1 to foreground
bg %2 # Resume paused job 2 in background
# Ctrl+Z — Suspend current foreground job and put in background
# Ctrl+C — Terminate foreground job
# nohup — Keep running after terminal closes
nohup node server.js &
nohup python app.py > app.log 2>&1 &
> ℹ️ 注意:`nohup` + `&`が永続的バックグラウンドコマンドの標準組み合わせ — `nohup`はSIGHUPシグナル(ターミナル終了時に送信)を無視し、`&`はバックグラウンド実行。出力はデフォルトで`nohup.out`に書き込まれます。ログファイルを手動指定することを推奨:`nohup command > app.log 2>&1 &`。
(5) ▶ サンプル:プロセスの確認
# View all processes
ps aux | head -10
# View processes for a specific user
ps -u alice -o pid,%cpu,%mem,comm
# Top 10 processes by CPU usage
ps aux --sort=-%cpu | head -11
# View process tree
ps auxf | head -20
出力:
TEXTUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.1 169344 13224 ? Ss 10:00 0:02 /sbin/init root 2 0.0 0.0 0 0 ? S 10:00 0:00 [kthreadd] alice 1234 0.3 1.2 123456 54321 ? Ssl 10:23 0:01 node server.js alice 2345 0.0 0.0 2345 567 pts/0 S+ 10:30 0:00 ps aux PID USER %CPU %MEM COMMAND 1234 alice 0.3 1.2 node 5678 bob 0.1 0.5 python3 USER PID %CPU %MEM COMMAND root 1 0.0 0.1 /sbin/init root 456 0.5 2.1 /usr/bin/containerd alice 1234 8.2 3.4 node server.js bob 2345 5.1 4.2 python train.py
(6) ▶ サンプル:リアルタイム監視
# Start top
top
# Operations inside top
# P → Sort by CPU
# M → Sort by memory
# k → Enter PID, press Enter, enter signal number (15 or 9), press Enter
# q → Quit
# Non-interactive mode
top -bn1 | head -15
出力:
TEXTtop - 10:30:01 up 5:23, 2 users, load average: 0.15, 0.10, 0.05 Tasks: 120 total, 1 running, 119 sleeping, 0 stopped, 0 zombie %Cpu(s): 2.3 us, 0.8 sy, 0.0 ni, 96.5 id, 0.2 wa, 0.0 hi, 0.2 si MiB Mem : 3936.0 total, 512.0 free, 2048.0 used, 1376.0 buff/cache
(7) ▶ サンプル:プロセスの終了
# Start a background process
sleep 1000 &
# Find it
ps aux | grep "sleep 1000"
# alice 5678 0.0 0.0 1234 567 pts/0 S 10:23 0:00 sleep 1000
# Graceful termination
kill 5678
# If that doesn't work
kill -9 5678
出力:
TEXT[1]+ Terminated sleep 1000 alice 5678 0.0 0.0 1234 567 pts/0 S 10:23 0:00 sleep 1000 [1]+ Killed sleep 1000
(8) ▶ サンプル:バックグラウンド実行の実践
# Start a long-running task
nohup python train_model.py > train.log 2>&1 &
# View the log
tail -f train.log
# Even after closing the terminal, train_model.py continues running
# After re-logging in, ps aux will show it's still running
出力:
TEXT[1] 5678 [2026-07-07 10:23:01] Training epoch 1/100... [2026-07-07 10:23:15] Loss: 0.5234 [2026-07-07 10:23:30] Training epoch 2/100...
(9) ▶ サンプル:nice/renice優先度調整
# nice range: -20 (highest priority) to 19 (lowest priority)
# Start with lower priority
nice -n 10 ./heavy-task
# Adjust priority of an existing process
renice -n 5 -p 1234
# View process nice values
ps -eo pid,nice,comm | head -10
(10) ▶ 総合例:サービス管理
#!/bin/bash
# manage-server.sh - Manage a Node.js application
APP_NAME="server.js"
APP_DIR="/home/alice/app"
PID_FILE="/tmp/app.pid"
start() {
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
echo "App is already running (PID: $(cat $PID_FILE))"
exit 1
fi
cd "$APP_DIR"
nohup node "$APP_NAME" > app.log 2>&1 &
echo $! > "$PID_FILE"
echo "App started (PID: $!)"
}
stop() {
if [ ! -f "$PID_FILE" ]; then
echo "App is not running"
exit 1
fi
PID=$(cat "$PID_FILE")
echo "Stopping app (PID: $PID)..."
kill "$PID" 2>/dev/null
sleep 2
if kill -0 "$PID" 2>/dev/null; then
echo "Force killing..."
kill -9 "$PID" 2>/dev/null
fi
rm -f "$PID_FILE"
echo "Stopped"
}
status() {
if [ -f "$PID_FILE" ] && kill -0 $(cat "$PID_FILE") 2>/dev/null; then
echo "Running (PID: $(cat $PID_FILE))"
ps -p $(cat "$PID_FILE") -o pid,%cpu,%mem,etime,comm
else
echo "Not running"
fi
}
case "${1:-status}" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
*) status ;;
esac
❓ よくある質問
Q: なぜ
kill -9は安全ではないのですか? A:kill -9(SIGKILL)はプロセスをクリーンアップなしで即座に強制終了します — 開いているファイルが破損、データベーストランザクションが中断、一時ファイルが残留する可能性があります。kill PID(SIGTERM)が応答しない場合のみ使用してください。
Q: ゾンビプロセスとは何ですか? A: 終了したが親プロセスが終了ステータスを読み取っていないプロセスです。プロセステーブルに「ゾンビ」エントリが残ります(STAT=Z)。ゾンビ自体はリソースを消費しませんが、多すぎるとプロセステーブルが枯渇します。通常、親プロセスをkillまたは再起動してクリーンアップします。
Q: nohupとdisownの違いは? A:
nohupは起動時にSIGHUPを無視するようプロセスを設定します(ターミナル終了時に送信)。disownはbash組み込みで、既に起動したジョブをシェルのジョブテーブルから削除します。nohup command &が最も一般的なアプローチ。
Q: プロセスのCPU使用率を制限するには? A:
cpulimitを使用:cpulimit -l 50 -p PIDで50%に制限。またはniceで優先度を下げる。Dockerコンテナでは--cpusで制限。
Q: 特定ポートを使用しているプロセスを見つけるには? A:
ss -tlnp | grep :PORT(推奨)、lsof -i :PORT(lsofが必要)、またはfuser PORT/tcp。
📖 まとめ
ps auxでプロセススナップショット、top/htopでリアルタイム監視- シグナル優先順位:SIGTERM(15) graceful終了 → SIGKILL(9)強制終了
&でバックグラウンド、jobs/fg/bgでジョブ管理nohup command &でターミナル終了後も継続実行nice -n 10 commandで優先度調整
📝 練習問題
- 基本(難易度 ⭐):
ps aux --sort=-%cpuでCPU使用率上位3プロセスを見つけ、sleep 300 &を起動し、jobsで確認し、killで終了する - 中級(難易度 ⭐⭐):
nohupで長時間実行コマンドを起動し、ターミナルを閉じ、再度開いてプロセスがまだ動いていることを確認する。次にss -tlnpで全リスニングポートと関連プロセスを確認する - 上級(難易度 ⭐⭐⭐):start/stop/status/restartコマンドをサポートするプロセス管理スクリプトを作成 — PIDファイルでプロセスを追跡し、graceful終了(SIGTERM、3秒待機、その後SIGKILL)を実装