du と df の違い - ディスク容量を正しく測る
この記事で解決できること
duとdfの 役割の違い が説明できる- 「
dfは満タンなのにduで計算しても合わない」現象の 原因 が分かる - 「削除したのに容量が戻らない」事件を 自力で解決 できる
- ディスクが足りなくなった時の 調査の型 が身につく
対象読者:Linux 入門者、du と df を「なんとなく」で使っている方
導入:リナのディスクパンク事件
リナ: ライニー先輩、大変です! サーバーのディスクが急に満タンになって、
du で大きいファイルを探したんですけど、合計しても全然容量が足りないんです。なんで?ライニー先輩: お、典型的な「
du と df のズレ」だね。これ、ちゃんと理解してない人めっちゃ多いよ。リナ: えっ、
du と df って似たコマンドじゃないんですか?ライニー先輩: そう見えるよね。でも実は 見ているものが全然違う んだ。今日はその違いと、ズレが起きる理由を一緒に見ていこう。
結論を先に
df= ファイルシステム単位 の空き容量(マウントポイントごと)du= ディレクトリ・ファイル単位 の使用量(指定パス以下を集計)- 一致しないのは 削除済み開きファイル / マウント境界 / root 予約ブロック が主因
df - ファイルシステム単位で空きを見る
ライニー先輩: まずは
df。「disk free」の略で、ファイルシステム(パーティションやマウントポイント)単位で「全体・使用済み・空き」を表示するよ。リナ: ファイルシステム単位...?
ライニー先輩: 簡単に言うと「マウントされてる場所」ごとだね。
/(ルート)、/home、USB メモリの /mnt/usb みたいに、別々にカウントされる。実際に試してみよう
$ df -h
Filesystem Size Used Avail Use% Mounted on /dev/sda1 50G 42G 5.5G 89% / tmpfs 1.9G 0 1.9G 0% /dev/shm /dev/sda2 100G 60G 40G 61% /home
読み方
Filesystem:デバイス名(/dev/sda1など)Size:全体容量Used:使用済みAvail:空きUse%:使用率(90% を超えたら警戒)Mounted on:マウントポイント
リナ:
-h ってなんですか?ライニー先輩:
--human-readable の略。50G とか 5.5G みたいに 人間が読みやすい単位 で表示してくれる。-h 付けない素の df は KB 表示なので、桁数えで疲れるよ。リナ: たしかに
52428800 とか出てきても分かんないですよね...よく使うオプション
$ df -h # 人間が読みやすい単位(G, M, K) $ df -T # ファイルシステムの種類も表示(ext4, xfs など) $ df -i # 使用量ではなく inode 数を表示 $ df -h /var # 特定パスが属するファイルシステムだけ
df -i を忘れない
ディスク容量に余裕があるのに「No space left」エラーが出る場合、inode の枯渇 が原因のことがある(大量の小さいファイルが原因)。
df -h と df -i は 両方確認する習慣 をつけよう。
du - ディレクトリ単位で使用量を測る
ライニー先輩: 次は
du。「disk usage」の略で、指定したディレクトリ以下のファイルを 実際に走査して 使用量を計算するよ。リナ: 走査するって、ファイルを 1 個ずつ見るってことですか?
ライニー先輩: そう。だから大きいディレクトリで
du を実行すると 時間がかかる ことがある。df が一瞬で返ってくるのと対照的だね。実際に試してみよう
$ du -sh /var/log
1.2G /var/log
よく使うオプションの組み合わせ
-s(summary):合計だけ表示-h(human-readable):人間が読める単位--max-depth=N:N 階層まで表示
-sh はワンセットで覚えると便利。
階層別に大きいディレクトリを探す
$ du -h --max-depth=1 /var
4.0K /var/games 1.2G /var/log 512M /var/cache 24M /var/lib 1.7G /var
リナ: これすごく便利ですね!
ライニー先輩: でしょ? さらに 大きい順にソート するとボス級ディレクトリが一目で見えるよ。
サイズ順に並べる
$ du -sh /var/* 2>/dev/null | sort -h
4.0K /var/games 4.0K /var/opt 24M /var/lib 512M /var/cache 1.2G /var/log
ポイント
2>/dev/null:権限不足で読めないディレクトリのエラーメッセージを捨てるsort -h:human-readable な単位を正しくソート(1.2Gが512Mより大きいと判定)
sort -n(数値ソート)だと 1.2G の 1.2 だけ見て小さい扱いになるので注意。
du と df の決定的な違い
リナ: なんとなく分かってきましたけど、結局何が違うんですか?
ライニー先輩: 一言で言うと 見方の階層が違う。図にすると分かりやすいよ。
比較表
| 項目 | df | du |
|---|---|---|
| 単位 | ファイルシステム | ディレクトリ・ファイル |
| 取得方法 | スーパーブロックから取得 | 実際にファイルを走査 |
| 速度 | 一瞬 | 大きいパスでは遅い |
| 削除済み開きファイル | 含まれる | 含まれない |
| 別マウント | 別物として集計 | 跨いで集計(-x で抑制可) |
| root 予約ブロック | 影響あり | 影響なし |
リナ: なるほど...だから「
df で 90% なのに du だと 60% しか使ってない」みたいなことが起こるんですね?ライニー先輩: その通り! よくある原因 3 つを次から詳しく見ていこう。
ズレの主犯:削除済み開きファイル事件
ライニー先輩:
df と du がズレる 一番多い原因 がこれ。「削除したのに、まだ誰かが開いているファイル」だよ。リナ: 削除したのに開いてる...? どういうことですか?
ライニー先輩: Linux は
rm でファイルを消しても、そのファイルを開いているプロセスがいる間は実体が残る んだ。たとえば、起動中の Web サーバーがログファイルを開いたまま、誰かが rm /var/log/access.log したケース。リナ: わ、ログファイルが消えたように見えて、実は容量を食い続けてるってことですか?
ライニー先輩: 正解。
du は ファイル名で辿れないから検出できない。でも df は ファイルシステム的にはまだ確保されてる から使用済みとしてカウントする。これがズレの正体。削除済み開きファイルを見つける
$ sudo lsof | grep deleted
nginx 1234 root 5w REG 8,1 524288000 ... /var/log/nginx/access.log (deleted) mysqld 5678 mysql 7w REG 8,1 104857600 ... /tmp/ibdata.tmp (deleted)
読み方
- 列 1:プロセス名(
nginx,mysqld) - 列 2:PID(プロセス ID)
- 列 7:サイズ(バイト単位)
- 末尾の
(deleted):削除済みなのに開かれている印
解放するには
# 該当プロセスを再起動 or リロード $ sudo systemctl restart nginx $ sudo systemctl reload mysql # プロセスが特定できれば、再起動なしで切り離す方法もある(上級者向け) # /proc/<PID>/fd/<N> を /dev/null にリダイレクトする手法など
再起動の前に必ず影響範囲を確認
本番サーバーで systemctl restart する前に、サービスダウンが許される時間帯か、依存サービスはあるかをチェック。詳しくは ディスクがいっぱい を参照。
ズレの第二犯:マウント境界
リナ: あと 2 つって何ですか?
ライニー先輩: 1 つはマウント境界。たとえば
/home が別パーティションになってる時、du -sh / するとどうなると思う?リナ: えーっと...
/home も含めて全部足される?ライニー先輩: そう、デフォルトでは マウントポイントを跨いで集計する。一方
df は別ファイルシステムなので別物としてカウント。だから du -sh / の数字が df の / の使用量より 大きく出る ことがある。# マウント境界を跨がない(その FS だけ集計) $ sudo du -sh -x /
-x(--one-file-system)
これを付けると du は 指定パスと同じファイルシステムだけ を集計する。df との比較がしやすくなる。
ズレの第三犯:root 予約ブロック
ライニー先輩: 最後は地味だけど大事。ext4 などのファイルシステムは root 用に 5% の領域を予約 しているんだ。
リナ: なんで予約するんですか?
ライニー先輩: 通常ユーザーが容量を食い尽くしても、root が緊急対応できるようにするため。
df の Avail はこの予約分を 差し引いた値 だから、Size - Used と Avail が一致しないように見える。# 予約ブロックの割合を確認 $ sudo tune2fs -l /dev/sda1 | grep -i reserved
Reserved block count: 655360 Reserved blocks uid: 0 (user root) Reserved blocks gid: 0 (group root)
予約ブロックを減らすのは慎重に
tune2fs -m 1 /dev/sda1 で 1% に減らせるが、システム領域では予約は 残しておくのが基本。データ専用パーティションのみ削減を検討する。
実務で使う「調査の型」
リナ: 違いは分かりました! じゃあ実際に「ディスクが足りない」って言われた時、どう動けばいいですか?
ライニー先輩: いい質問。手順を型化しておくと事故らないよ。
ディスク調査の型(上から順に)
- 全体を俯瞰:
df -h(どのファイルシステムが満タンか) - inode も確認:
df -i(小さいファイル大量問題) - 大きいディレクトリを特定:
sudo du -h --max-depth=1 / 2>/dev/null | sort -h dfとduがズレてたら:sudo lsof | grep deleted- 古いログを削除:
/var/log配下の.gzなどを確認 - 解放されない時:該当サービスを
systemctl restart
各ステップのコマンド集
# 1. 全体を俯瞰 df -h # 2. inode 確認 df -i # 3. 大きいディレクトリ特定(root から 1 階層ずつ深掘り) sudo du -h --max-depth=1 / 2>/dev/null | sort -h sudo du -h --max-depth=1 /var 2>/dev/null | sort -h sudo du -h --max-depth=1 /var/log 2>/dev/null | sort -h # 4. 削除済み開きファイル sudo lsof | grep deleted | sort -k7 -n -r | head # 5. 大きいファイル単位で探す sudo find / -type f -size +100M 2>/dev/null
ミニ課題:自分の環境で試してみよう
ライニー先輩: 知識を定着させるために、自分の環境で次の課題をやってみよう。
課題 1:自分の / パーティションの使用率を確認する
課題 2:ホームディレクトリ直下で 最も大きいディレクトリ Top 3 を見つける
課題 3:df -h と sudo du -sh -x / の数字を比較し、差分が出る理由を 1 行で説明する
課題 1 のヒント
df -h /
Use% 列が / の使用率。90% を超えたら片付けを検討。
課題 2 のヒント
du -h --max-depth=1 ~ 2>/dev/null | sort -h | tail -3
tail -3 で大きい順 Top 3 を抽出。
課題 3 のヒント
差分が出る主な理由:
- 削除済みだが開いているファイル(
dfのみカウント) - 別マウントポイントの存在(
du -xで除外していない場合) - ext4 の root 予約ブロック(
dfのAvailに影響)
よくある落とし穴
やってはいけない 3 つのパターン
du -sh /をnohupなしで本番で実行 → SSH 切断で途中停止dfの数字だけ見てファイルを消す → 削除済み開きファイルが原因の時は無意味rm -rf /tmp/*で全削除 → 起動中のアプリの作業ファイルを壊す
安全な型
sudo du -sh /*で トップレベルから順に深掘り(一気にルート以下を走らない)- 消す前に
ls -lhで サイズと更新日時を確認 - 大きいログは消すより
truncate -s 0 ファイル名で 中身だけ空にする(プロセスが開いていてもセーフ)