「Linuxサーバーのメモリが気づいたら減っている」
「slabtopを見たらdentryが大量にある」
「そもそもdentryって何?」
こんな経験をしたことはありませんか。
dentryキャッシュはLinuxカーネルの中でも地味ながら重要な仕組みで、ファイルアクセスの速度に直接影響します。
この記事では、dentryキャッシュの役割・仕組み・メモリへの影響・運用上の対処法まで、一通り解説します。
dentryとは何か
dentryとは、directory entry(ディレクトリエントリ)の略で、LinuxカーネルのVFS(Virtual File System、仮想ファイルシステム)が使う構造体のひとつです。
VFSはext4・XFS・Btrfsなど異なるファイルシステムを統一的に扱うための中間層で、dentryはその中で「ファイル名・ディレクトリ名とinode(実体)を結びつける」役割を持ちます。
inodeとdentryの違い
Linuxのファイルシステムには、大きく分けて2種類の管理情報があります。
| 構造体 | 役割 | 保持する情報の例 |
|---|---|---|
| inode | ファイルの実体を管理 | ファイルサイズ、パーミッション、タイムスタンプ、ディスク上の位置など |
| dentry | 名前と実体を結びつける | ファイル名・ディレクトリ名、親dentryへの参照、inodeへの参照 |
重要なのは、ファイル名はinodeではなくdentryが持つという点です。
inodeはファイルの実体の情報だけを管理し、「どんな名前でアクセスされているか」は知りません。
dentryがその橋渡しをすることで、ハードリンクのように「複数の名前が同じinodeを指す」構造も実現できています。
dentryキャッシュが必要な理由
Linuxのディレクトリ構造でも触れているとおり、Linuxのパスは/var/log/nginx/access.logのように階層構造になっています。
このパスにアクセスするとき、カーネルは内部で以下の処理を行います。
/(ルート)のdentryを確認するvarのinodeをディスクから検索してdentryを作成するlogのinodeをディスクから検索してdentryを作成するnginxのinodeをディスクから検索してdentryを作成するaccess.logのinodeをディスクから検索してdentryを作成する
階層が深くなるほど、ディスクI/Oが何度も発生します。
ディスクアクセスはメモリアクセスと比べて数百倍〜数千倍遅いため、毎回これをやっていては処理速度が大幅に落ちます。
そこでLinuxカーネルは、一度生成したdentryをメモリ上のキャッシュ(dentryキャッシュ)として保持し、同じパスへの2回目以降のアクセスはキャッシュから返すようにしています。
実際にls -R /を実行すると、キャッシュが温まった2回目以降は10倍以上高速になることが確認されています。
dentryキャッシュの仕組み
ハッシュテーブルで管理
dentryキャッシュはハッシュテーブルで管理されています。
検索キーは「親dentryのアドレス + ファイル名のハッシュ値」の組み合わせです。
これによりあるディレクトリ内の特定のファイル名を高速に検索できます。
検索関数はd_lookup()と呼ばれ、ヒットした場合は参照カウントを増やしてdentryを返します。
キャッシュに存在しない場合はNULLを返し、カーネルはディスクから実際に検索します。
dentryの状態
dentryは以下の3つの状態を持ちます。
- 使用中(in-use):いずれかのプロセスが現在参照している状態。解放されない
- 未使用(unused):参照カウントが0だが、キャッシュとして保持している状態。メモリ不足時に最初に回収される
- ネガティブ(negative):存在しないパスに対して作られたdentry(後述)
ネガティブdentryとは
stat /etc/hoge_not_existのように存在しないパスへのアクセスが発生した場合、Linuxはディスクへの問い合わせの結果「ファイルが存在しない」という情報も、空のdentry(ネガティブdentry)としてキャッシュします。
なぜ存在しないものをキャッシュするかというと、「このパスは存在しない」という事実を覚えておくことで、次回同じパスにアクセスされたときにディスクI/Oを省略できるからです。
DNSのネガティブキャッシュと同じ発想です。
ただし、ランダムなファイル名を大量に生成・削除するアプリケーション(画像変換ツールなど)では、同じパスが再利用されないためネガティブdentryが溜まる一方になり、メモリを圧迫する原因になります(詳細は後述)。
Slabアロケータとdentryの関係
dentryはカーネルのSlabアロケータによって管理されます。
Slabアロケータとは、同じサイズのオブジェクトをまとめて確保・再利用するカーネルのメモリ管理機構です。
/proc/meminfoのSlabフィールドがその使用量の合計で、slabtopコマンドでdentryの内訳を確認できます。
# Slabキャッシュの内訳を確認(要root権限)
sudo slabtop
出力例(上位項目):
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
123456 120000 97% 0.19K 3090 40 24720K dentry
56789 55000 96% 0.61K 1828 31 29248K inode_cache
RHELではdentry_cache(RHEL4・5)またはdentry(RHEL6以降)という名前で表示されます。
dentryキャッシュの確認方法
/proc/sys/fs/dentry-state
/proc/sys/fs/dentry-stateを読むと、dentryキャッシュの現在の状態を数値で確認できます。
cat /proc/sys/fs/dentry-state
出力形式:
nr_dentry nr_unused age_limit want_pages dummy dummy
nr_dentry:現在確保されているdentryの総数nr_unused:参照カウントが0のdentry数(解放候補)want_pages:カーネルがdentryの縮小を要求しているページ数
/proc/meminfoでSlabを確認
Linuxのスペック確認コマンドでも紹介しているとおり、/proc/meminfoでSlab全体のサイズを確認できます。
cat /proc/meminfo | grep -E "Slab|SReclaimable|SUnreclaim"
Slab:Slabキャッシュの合計SReclaimable:メモリ不足時に回収できる部分(dentryキャッシュはここに含まれる)SUnreclaim:回収できない部分
dentryキャッシュの肥大化と対処法
肥大化が起きるケース
dentryキャッシュは通常、メモリが不足してくるとカーネルが自動で回収します。
ただし、以下のような状況では想定外に大量のdentryが蓄積することがあります。
- 大量の一時ファイルをランダムな名前で作成・削除し続けるアプリ(画像変換、ログローテーションなど)
- 大量のファイルがあるディレクトリを
findなどで全走査するバッチ処理 - 存在しないパスへのアクセスが多発するアプリケーション
いずれも大量のdentry(特にネガティブdentry)が生成され、回収が追いつかない状態になります。
対処法1:vfs_cache_pressureを調整する
vm.vfs_cache_pressureはカーネルがdentryとinodeキャッシュをどの程度積極的に回収するかを制御するパラメータです。
| 値 | 動作 |
|---|---|
0 | 絶対に回収しない(OOMの原因になりうる) |
100(デフォルト) | ページキャッシュと同等の優先度で回収 |
100より大きい | より積極的に回収する |
# 現在の値を確認
cat /proc/sys/vm/vfs_cache_pressure
# 一時的に変更(再起動で元に戻る)
sudo sysctl -w vm.vfs_cache_pressure=200
# 恒久的に変更(/etc/sysctl.confに追記)
echo "vm.vfs_cache_pressure=200" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
対処法2:drop_cachesで強制解放する
/proc/sys/vm/drop_cachesに値を書き込むと、キャッシュを強制的に解放できます。
# 実行前にsyncで書き込みを確定させる(重要)
sync
# 2:dentryキャッシュとinodeキャッシュを解放
echo 2 | sudo tee /proc/sys/vm/drop_caches
# 3:ページキャッシュ・dentryキャッシュ・inodeキャッシュをまとめて解放
echo 3 | sudo tee /proc/sys/vm/drop_caches
注意:drop_cachesは本番環境での常用は推奨されません。
解放直後はキャッシュが空になるため、ファイルアクセスのたびにディスクI/Oが発生し、一時的にパフォーマンスが低下します。
根本対策(後述)を先に検討してください。
対処法3:tmpfsを使う
一時ファイルを大量に作成・削除するアプリが原因の場合、tmpfs(メモリ上のファイルシステム)に一時ディレクトリを移すと効果的です。
tmpfsではすべてのデータがメモリ上に保持されるため、ディスクへのI/Oが不要でネガティブdentryもキャッシュされません。unlinkでファイルを削除するとdentryも即座に破棄されます。
# /dev/shmはデフォルトでtmpfsがマウントされている
export TMPDIR=/dev/shm
# アプリの一時ディレクトリをtmpfsに変更する例
java -Djava.io.tmpdir=/dev/shm MyApp
対処法4:根本原因を特定して解消する
肥大化の根本は不要なファイルの蓄積や過剰なパス検索であることが多いです。
特定のアプリがどのパスを大量に作成・アクセスしているかは、SystemTapやbpftraceといったトレースツールで調査できます。
ログファイルなどが原因なら、定期的なローテーション・削除バッチを見直すと解決するケースが多いです。
まとめ
dentryキャッシュはLinuxのパス名検索を高速化するVFSの仕組みです。
ポイントを整理します。
- dentryはファイル名・ディレクトリ名とinodeを結びつける構造体
- 一度アクセスしたパスはキャッシュとして保持され、2回目以降のI/Oを省略する
- 存在しないパスはネガティブdentryとしてキャッシュされ、無駄なディスクI/Oを防ぐ
- キャッシュはSlabアロケータが管理し、
slabtopや/proc/meminfoで確認できる - 大量のランダムな一時ファイル作成・削除が原因で肥大化するケースが多い
- 対処法は
vfs_cache_pressureの調整・drop_caches・tmpfsへの移行・根本原因の特定
通常はカーネルが自動で回収するため意識する機会は少ないですが、サーバーのメモリが徐々に圧迫される現象に遭遇したときは、まずslabtopでdentryキャッシュの状況を確認してみてください。
ディスク容量の確認方法はLinuxのストレージ容量確認コマンド完全ガイドも参考にしてください。
参考情報源:
- Linux Kernel documentation「Overview of the Linux Virtual File System」 (kernel.org)
- ITmedia「ファイル名を管理するキャッシュdentry」 (2011年)
- OSDN「Linux Kernel Documents – ディレクトリエントリキャッシュ」
- DeNA Engineering「Slabキャッシュの使用量が増加した原因をSystemTapで調査した」
- Red Hat Customer Portal「dentry_cache/dentry slab cache size continually grows」
- Major Hayden「Reducing inode and dentry caches to keep OOM killer at bay」

コメント