du と df の違い - ディスク容量を正しく測る

du と df の違い - ディスク容量を正しく測る

この記事でできるようになること

  • `df` はファイルシステム単位、`du` はディレクトリ単位という視点の違いを説明できる
  • `df -h` `df -i` `du -sh` `du -h --max-depth=1` を目的に応じて使い分けられる
  • `df` と `du` がズレる 3 つの原因を挙げ、`lsof | grep deleted` で確かめられる

前提知識(先に読むと理解しやすい記事)

この記事で解決できること

  • dudf役割の違い を説明できます
  • df は満タンなのに du で計算しても合わない」現象の 原因 が分かります
  • 「削除したのに容量が戻らない」事件を 自力で解決 できます
  • ディスクが足りなくなったときの 調査の型 が身につきます

対象読者:Linux 入門者。dudf を感覚で使い分けている方。

言葉の整理

  • ファイルシステム:ディスクを区切って使うための仕組みです。この記事では「//home のように独立して容量を数える単位」と考えてください。
  • マウント:ディスクをディレクトリファイルをまとめて整理する入れ物。Windows や macOS の「フォルダ」と同じもの。に結びつけて使える状態にすることです。結びつけた場所を「マウントポイント」と呼びます。
  • inode:ファイル 1 つ 1 つの管理情報を入れる札です。札の数には上限があります。
  • プロセス:実行中のプログラムのことです。
  • sudo:管理者の権限でコマンドを実行するための命令です。他人のファイルを調べるときに必要です。実行するとパスワードを聞かれることがあります。
  • パイプ(|:左のコマンドの結果を右のコマンドに渡す記号です。A | B で「A の結果を B で処理する」という意味になります。
  • grep:文字を探し出すコマンドです。grep deleted なら「deleted という文字を含む行だけ残す」という意味です。

この記事の中心は dfdu です。どちらも表示するだけのコマンドで、ファイルを消したり書きかえたりしません。何度実行してもディスクの中身は変わりません。安心して試してください。

なお、記事の後半には削除や再起動をともなうコマンドも出てきます。そこには個別に注意書きを付けています。

導入:リナのディスクパンク事件

リナ: ライニー先輩、大変です。サーバーのディスクが急に満タンになりました。
リナ: du で大きいファイルを探したんですけど、合計しても全然容量が足りません。どうしてですか?
ライニー先輩: 典型的な「dudf のズレ」だね。これを正しく理解している人は意外と少ないんだ。
リナ: えっ、dudf って似たコマンドじゃないんですか?
ライニー先輩: そう見えるよね。でも 見ているものが違う んだ。今日はその違いと、ズレが起きる理由を見ていこう。

結論を先に

2 つの視点のたとえ

冷蔵庫を思いうかべてください。df は「冷蔵庫にどれだけ空きがあるか」を外から見る係です。du は「棚ごとに何がどれだけ入っているか」を中から数える係です。

同じ冷蔵庫を見ていますが、数え方が違います。だから答えがずれることがあります。

df - ファイルシステム単位で空きを見る

結論: df はマウントポイントごとに全体・使用・空きを一瞬で表示する。-h-i の両方を確認する。

ライニー先輩: まずは 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 の略だよ。50G5.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 -hdf -i両方確認する習慣 をつけましょう。

du - ディレクトリ単位で使用量を測る

結論: du はファイルを実際に走査して使用量を計算する。-sh で合計、sort -h で大きい順に並ぶ。

ライニー先輩: 次は 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単位付きの数字を正しく並べます1.2G512M より大きいと判定します)

sort -n(数値ソート)には注意が必要です。1.2G1.2 だけを見るため、小さい扱いになります。

du と df の決定的な違い

結論: df はファイルシステム単位、du はディレクトリ単位で見る。見ている階層が違うのでズレる。

リナ: だいぶ分かってきました。結局、何が違うんですか?
ライニー先輩: 一言で言うと 見ている階層が違う んだ。表にすると分かりやすいよ。

比較表

項目 df du
単位 ファイルシステム ディレクトリ・ファイル
取得方法 スーパーブロックから取得 実際にファイルを走査
速度 一瞬 大きいパスでは遅い
削除済み開きファイル 含まれる 含まれない
別マウント 別物として集計 跨いで集計(-x で抑制可)
root 予約ブロック 影響あり 影響なし
リナ: なるほど。だから「df では 90% なのに、du では 60% しか使っていない」ということが起こるんですね。
ライニー先輩: そのとおり。よくある原因は 3 つある。次から詳しく見ていこう。

ズレの主犯:削除済み開きファイル事件

結論: 削除しても開いているファイルは df だけがカウントする。lsof | grep deleted で見つけて解放する。

ライニー先輩: dfdu がズレる 一番多い原因 がこれだよ。「削除したのに、まだ誰かが開いているファイル」だね。
リナ: 削除したのに開いている、ですか。どういうことでしょう。

リナの失敗:ログを消したのに容量が戻らない

リナ: 実は今日、/var/log/nginx/access.logrm で消しました。500 MB もあったのに、df -h の空き容量が 1 バイトも増えません。消し方を間違えたんでしょうか。
$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   42G  5.5G  89% /
リナ: えっ、ファイルは一覧から消えているのに、使用量は 42G のままです。消えていないんでしょうか。
ライニー先輩: 消し方は間違っていないよ。Linux では、rm してもファイルの実体がすぐには消えないことがあるんだ。
ライニー先輩: そのファイルを開いているプロセスがいる間、実体は残り続ける。今回は起動中の nginx が、そのログを開いたままなんだよ。
リナ: 名前だけ消えて、中身は残っているんですね。それは想像していませんでした。
ライニー先輩: そう。du は名前をたどって数えるから、この分を見つけられない。df はファイルシステムから見た使用量だから、この分を数えるんだ。
リナ: 納得しました。dfdu がズレたら、まず開きっぱなしのファイルを疑います。
ライニー先輩: つまり rm は「名前を消すコマンド」と考えるといい。実体が解放されるのは、それを開いている全員が閉じたあとだよ。

削除済み開きファイルを見つける

$ 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):削除済みなのに開かれている印です

lsof は「list open files」の略です。開かれているファイルを一覧するコマンドで、表示するだけです。実行してもファイルは変わりません。

解放するには

# 該当プロセスを再起動 or リロード
$ sudo systemctl restart nginx
$ sudo systemctl reload mysql

# プロセスが特定できれば、再起動なしで切り離す方法もある(上級者向け)
# /proc/<PID>/fd/<N> を /dev/null にリダイレクトする手法など

再起動の前に必ず影響範囲を確認

systemctl restart はサービスをいったん止めます。失敗すると、その間サービスが応答しなくなります。

本番サーバーで実行する前に、次の 2 点を確認してください。

  • サービスが止まってよい時間帯か
  • そのサービスに依存している別のサービスはないか

安全に試したい場合は、まず学習用の環境か、止めても影響のないサービスで練習してください。詳しくは ディスクがいっぱい を参照してください。

ズレの第二犯:マウント境界

結論: du は既定でマウント境界を跨いで集計する。df と揃えるには -x を付けて同一 FS に限定する。

リナ: あと 2 つは何ですか?
ライニー先輩: 1 つはマウント境界だね。たとえば /home が別パーティションになっているとしよう。そこで du -sh / を実行すると、どうなると思う?
リナ: /home も含めて全部足される、でしょうか。
ライニー先輩: そのとおり。du は既定で マウントポイントを跨いで集計する んだ。
ライニー先輩: 一方 df は別ファイルシステムを別物として数える。だから du -sh / の数字が、df/ の使用量より 大きく出る ことがあるんだよ。
# マウント境界を跨がない(その FS だけ集計)
$ sudo du -sh -x /

-x--one-file-system

これを付けると du指定パスと同じファイルシステムだけ を集計します。df との比較がしやすくなります。

ズレの第三犯:root 予約ブロック

結論: ext4 は root 用に約 5% を予約する。dfAvail は予約分を差し引くため数字が合わない。

ライニー先輩: 最後は地味だけど大事な話だよ。ext4 などのファイルシステムは root 用に 5% の領域を予約 しているんだ。
リナ: どうして予約するんですか?
ライニー先輩: 通常ユーザーが容量を使い切っても、root なら緊急の対応ができるようにするためだよ。
ライニー先輩: dfAvail はこの予約分を 差し引いた値 なんだ。だから Size - UsedAvail が一致しないように見えるんだよ。
# 予約ブロックの割合を確認
$ 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% に減らせます。ただし、この操作はファイルシステムの設定を書きかえます。

システム領域では予約を 残しておくのが基本 です。減らすとしても、データ専用パーティションだけにしてください。

なお tune2fs -l(一覧表示)は読むだけの操作です。設定は変わりません。

実務で使う「調査の型」

結論: df -h で俯瞰、df -i で inode 確認、du で大きいディレクトリ特定、lsof でズレ調査の順に動く。

リナ: 違いは分かりました。実際に「ディスクが足りない」と言われたとき、どう動けばいいですか?
ライニー先輩: いい質問だね。手順を型として決めておくと、あわてずに済むよ。

ディスク調査の型(上から順に)

  1. 全体を俯瞰df -h(どのファイルシステムが満タンか)
  2. inode も確認df -i(小さいファイル大量問題)
  3. 大きいディレクトリを特定sudo du -h --max-depth=1 / 2>/dev/null | sort -h
  4. dfdu がズレてたらsudo lsof | grep deleted
  5. 古いログを削除/var/log 配下の .gz などを確認
  6. 解放されない時:該当サービスを 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

ミニ課題:自分の環境で試してみよう

結論: 使用率確認・大きいディレクトリ Top3・dfdu の差分説明の 3 問で理解を定着させる。

リナ: 知識は入りました。手を動かして試したいです。
ライニー先輩: いいね、3 問用意したよ。どれも表示するだけの操作だから、何度実行してもディスクは変わらないよ。
ライニー先輩: ただし、この章のコマンドは実機の Linux か WSL で試してほしい。lsof--max-depth は本サイトの仮想ターミナル入力したコマンドを解釈してコンピュータに実行させる対話プログラム。には入っていないんだ。
ライニー先輩: sudo が使えない環境なら、自分のホームディレクトリの中だけで試そう。

課題 1: 自分の / パーティションの使用率を確認しよう。

ヒント 1(方向づけ)を見る

ファイルシステム単位で空きを見る側のコマンドを使います。ディレクトリを 1 つずつ数える必要はありません。

読みやすい単位で表示するオプションも付けます。

ヒント 2(コマンド名)を見る

使うのは df です。読みやすい単位は -h です。調べたい場所として / を指定します。

答えを見る
$ df -h /
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1        50G   42G  5.5G  89% /

Use% の列が / の使用率です。90% を超えたら片づけを検討してください。

課題 2: ホームディレクトリの直下で、最も大きいディレクトリ Top 3 を見つけよう。

ヒント 1(方向づけ)を見る

今度はディレクトリごとに数える側のコマンドを使います。深くもぐらず、1 階層だけ見れば十分です。

そのうえで大きい順に並べ、末尾の数行を取り出します。

ヒント 2(コマンド名)を見る

使うのは du です。階層を 1 つに絞るのは --max-depth=1 です。並べかえは sort -h です。

末尾の行を取り出すのは tail です。一番下は全体の合計になるので、1 行多めに取ります。ホームディレクトリは ~ と書けます。

答えを見る
$ du -h --max-depth=1 ~ 2>/dev/null | sort -h | tail -4
64M     /home/user/Documents
512M    /home/user/Downloads
1.2G    /home/user/Videos
2.5G    /home/user

sort -h は小さい順に並べます。だから末尾を取れば大きい方が取れます。

一番下の行はホームディレクトリ全体の合計です。その上の 3 行が Top 3 です。だから tail -4 にしています。

課題 3: df -h /sudo du -sh -x / の数字を比べ、差が出る理由を 1 行で説明しよう。

ヒント 1(方向づけ)を見る

まず 2 つの数字を並べて見ます。そのうえで、この記事で挙げた 3 つの原因を思い出してください。

どちらか一方だけが数えるものがあります。

ヒント 2(コマンド名)を見る

df -h /sudo du -sh -x / を続けて実行します。差が大きいときは sudo lsof | grep deleted も実行します。

答えを見る
$ df -h /
$ sudo du -sh -x /
$ sudo lsof | grep deleted | head

差が出る主な理由は次の 3 つです。

  • 削除済みだが開いているファイル(df だけが数えます)
  • 別のマウントポイントの存在(du -x で除外していない場合)
  • ext4 の root 予約ブロック(dfAvail に影響します)

1 行でまとめるなら「df はファイルシステムから見た使用量、du は名前をたどった使用量なので、名前のないデータの分だけずれる」となります。

よくある落とし穴

結論: df の数字だけで消す・全削除する操作は危険。消す前に ls -lh で確認し truncate も検討する。

やってはいけない 3 つのパターン

  1. du -sh /nohup なしで本番で実行する → SSH が切れると途中で止まります
  2. df の数字だけを見てファイルを消す → 削除済み開きファイルが原因のときは効果がありません
  3. rm -rf /tmp/* で全部を消す → 起動中のアプリの作業ファイルを壊します

安全な型

  • du はどの書き方でも、指定した場所より下をすべて数えます。走査量そのものは減りません
  • 表示だけを絞るなら sudo du -h --max-depth=1 / 2>/dev/null | sort -h を使います。1 階層ごとの合計が見えるので、次にどこを掘るか決められます
  • 時間がかかる調査は tmuxscreen の中で実行します。接続が切れても止まりません
  • 消す前に ls -lhサイズと更新日時を確認します
  • 大きいログは消さず、truncate -s 0 ファイル名中身だけを空にします

3 つ目について補足します。truncate -s 0 はファイルの中身を空にする操作です。中身は戻せません。ただし、ファイル自体は残るため、プロセスが開いたままでも安全に容量を解放できます。

先に ls -lh でサイズを見て、消してよい内容かを確かめてから実行してください。

振り返り

リナ: 整理します。df はファイルシステム単位、du はディレクトリ単位で数えるんですね。
ライニー先輩: そのとおり。同じディスクを、外から見るか中から数えるかの違いだね。
リナ: ログを消しても容量が戻らなかったのは、nginx がそのファイルを開いたままだったからでした。
ライニー先輩: よく覚えていたね。ズレを見つけたら sudo lsof | grep deleted を先に実行する。この順番だけ覚えておけば大丈夫だよ。

今日の 3 行まとめ

  1. df はファイルシステム単位の空き、du はディレクトリ単位の使用量を見る
  2. ズレの主な原因は「削除済み開きファイル」「マウント境界」「root 予約ブロック」の 3 つ
  3. 調べる順番は df -hdf -idu --max-depth=1lsof | grep deleted

次に読む

この記事を共有

次の一手