Linuxサーバーを運用していると、topコマンドや/proc/meminfoで「Slab」という項目を見かけることがあります。
プロセスが使っているわけでもないのにメモリが減っていく——その正体がslabキャッシュです。
この記事では、slabキャッシュの仕組み・確認方法・クリア方法までをまとめて解説します。
slabキャッシュとは
Linuxカーネルは、メモリの利用効率を高めるために、カーネル空間内でよく使うオブジェクトをあらかじめキャッシュしておく仕組みを持っています。
これをslabキャッシュ(Slab Cache)と呼びます。
通常のユーザープロセスが使うメモリとは別に、カーネル自身が内部処理のために確保するメモリ領域で、topコマンドやpsコマンドには表示されません。
なぜslabキャッシュが必要なのか
カーネルは内部処理のたびに、ファイル情報・ディレクトリ情報・プロセス管理構造体などのオブジェクトを大量に生成・破棄します。
このたびに物理メモリから空き領域を探して割り当て、使用後に解放するという処理を繰り返すと、コストが高くパフォーマンスに影響が出ます。
slabキャッシュはこの問題を解決するために、よく使うオブジェクトをあらかじめメモリ上に用意しておき、必要になったらすぐに渡せる状態にしておきます。
使い終わったオブジェクトはすぐに破棄せず、キャッシュに戻して再利用します。
slabキャッシュの歴史と実装の種類
slabアロケーションは1994年にJeff Bonwick氏によって開発され、Solaris 2.4カーネルで最初に導入されました。
Linuxカーネルにはバージョン2.2から採用されています。
現在のLinuxカーネルには、以下の3種類のslabアロケーターが存在します。
| 名前 | 説明 |
|---|---|
| SLOB | 最初期の実装。メモリの少ない組み込みシステム向けに現在も残る |
| SLAB | SLOBの後継。Linuxカーネル2.6.23まで標準アロケーター |
| SLUB | 現在のデフォルト。SLABの複雑な構造を簡略化した改良版 |
現在のLinuxではSLUBが標準で使われています。
slabキャッシュの構造
slabキャッシュは3つの階層で構成されています。
Cache(キャッシュ)
特定の種類のオブジェクトをまとめて管理する単位です。
たとえば「dentry用キャッシュ」「inode用キャッシュ」のように、オブジェクトの種類ごとにキャッシュが用意されています。
Slab(スラブ)
1つ以上の連続した物理メモリページで構成される、実際のデータ格納領域です。
1つのCacheは複数のSlabを持ちます。
各Slabは以下のいずれかの状態にあります。
- Empty(空):オブジェクトがすべて空き状態
- Partial(一部使用中):空きオブジェクトと使用中オブジェクトが混在
- Full(満杯):すべてのオブジェクトが使用中
Object(オブジェクト)
Slabの中に並ぶ個々のデータ実体です。
主にキャッシュされるオブジェクト
slabキャッシュが管理する主なオブジェクトは以下のとおりです。
- dentry:ディレクトリ名・ファイル名とinodeを結びつけるキャッシュ
- inode:ファイルの所有者・パーミッション・タイムスタンプなどのメタデータ
- task_struct:プロセス管理に使われる構造体
- kmalloc-xxx:
kmalloc()呼び出しに使われる汎用的な小サイズキャッシュ
なかでもdentryとinodeはメモリ使用量が増大しやすく、サーバー運用上の監視対象になりやすいオブジェクトです。findコマンドやupdatedb(mlocate)を大量のファイルに対して実行すると、これらのキャッシュが急激に膨らむことがあります。
SReclaimableとSUnreclaim
/proc/meminfoのSlab行は、さらに2つに分けられます。
| 項目 | 意味 |
|---|---|
| SReclaimable | 回収可能なslabキャッシュ。dentryやinodeなど、ストレージと同期済みであれば解放できるもの |
| SUnreclaim | 回収不可なslabキャッシュ。カーネルが継続的に必要とするオブジェクトで、解放できない |
Slab = SReclaimable + SUnreclaim の関係になります。
メモリ圧迫が問題になるのは大半がSReclaimableの肥大化によるもので、SUnreclaimが増え続ける場合はカーネルレベルのメモリリークを疑う必要があります。
slabキャッシュの確認方法
/proc/meminfoで確認
cat /proc/meminfo | grep -E "Slab|SReclaim|SUnreclaim"
出力例:
Slab: 278386 kB
SReclaimable: 205440 kB
SUnreclaim: 72946 kB
slabtopコマンドで確認
オブジェクト種別ごとの詳細を確認するにはslabtopコマンドを使います。
# リアルタイム表示
slabtop
# 1回だけ表示してキャッシュサイズ順にソート
slabtop --once --sort=c
出力例:
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1078560 1078560 100% 0.19K 51360 21 205440K dentry
22050 13007 58% 1.06K 1470 15 23520K xfs_inode
/proc/slabinfoでも同様の情報を確認できます。
slabキャッシュのクリア方法
/proc/sys/vm/drop_cachesに数値を書き込むことでキャッシュをクリアできます。
# slabキャッシュ(dentryとinode含む)をクリア
echo 2 > /proc/sys/vm/drop_caches
# ページキャッシュ+slabキャッシュの両方をクリア
echo 3 > /proc/sys/vm/drop_caches
クリア前にsyncを実行しておくと、より多くのキャッシュを解放できます。
sync && echo 2 > /proc/sys/vm/drop_caches
注意: このキャッシュクリアはパフォーマンスに影響が出る可能性があります。
本番環境で実行する場合は、タイミングを慎重に選ぶ必要があります。
また、クリア後しばらくするとキャッシュは再び生成されるため、根本的な対策にはならない点も留意してください。
まとめ
slabキャッシュは、Linuxカーネルがdentryやinodeなどのオブジェクトを使いまわすことでメモリ割り当てを高速化する仕組みです。topやpsでは見えないカーネル専用のメモリ領域で、slabtopコマンドや/proc/meminfoで確認できます。
サーバーのメモリ使用量が原因不明で増え続ける場合は、まずSReclaimableとSUnreclaimの内訳を確認するのが調査の第一歩になります。
関連するLinuxメモリ管理の仕組みについては、ページキャッシュやバディアロケーターの解説記事もあわせてご覧ください。
参考情報源:

コメント