Linuxのメモリ管理:スワップ、OOMキラー、Cグループ
12分で読めます - 2026年5月31日

Linuxスワップ、OOMキラー、cgroupsがどのように連携するか - データベース、ウェブサーバー、マルチテナントVPSホストの設定例付き。
Linuxのメモリ管理解説:スワップ、OOMキラー、cgroups
Linuxは、他の多くのオペレーティングシステムとは異なる方法でメモリを扱います。RAMの使用率が高いことが必ずしも問題になるわけではありません。カーネルは、ディスク読み取りを高速化するために、空きメモリをキャッシュとして積極的に利用します。しかし、実際のメモリ負荷が高まると、スワップ、OOMキラー、cgroupsという3つのメカニズムが機能します。それぞれの動作や設定方法を理解することは、負荷がかかっても正常に動作し続けるサーバーと、予告なしにクラッシュしてしまうサーバーとの違いを左右します。
Linuxによるメモリページの管理
すべてのプロセスは、64ビットシステムでは最大128TBまでの独自の仮想アドレス空間で実行されます。カーネルはページテーブルを通じてこれらの仮想アドレスを物理RAMにマッピングし、翻訳サイドバッファ(TLB)が最近の参照をキャッシュします。TLBヒットには約1ナノ秒かかりますが、ミスの場合は20~100ナノ秒を要し、データベースのようなメモリを多用するワークロードではこれが累積します。
物理メモリは4KBのページに分割され、カーネルはそれらを次の2つのカテゴリに分類します:
- ファイルバックアップページ — ディスク上のファイルに関連付けられています。カーネルは、スワップを必要とせずに、クリーンなページを破棄したり、ダーティなページをフラッシュしたりできます。
- 匿名ページ — バックファイルを持たないヒープおよびスタックメモリ。カーネルがこれらを解放するには、まずスワップ領域に書き出す必要があります。
メモリ需要の高いサーバーでは、匿名ページの割合が高くなると、スワップが早期に利用されることになります。 si (swap in) および so (swap out) 列を vmstat 1 — これらの値がゼロ以外で継続的に表示される場合は、システムに負荷がかかっている最初の兆候です。
監視には、適切なツールを使用してください:
| ツール | 最適用途 | 主な指標 |
|---|---|---|
free -h | システム全体の迅速なスナップショット | available 列 |
vmstat 1 | リアルタイムのスワップおよびI/Oモニタリング | si, so |
htop | プロセスごとのインタラクティブな表示 | メモリバー、プロセス一覧 |
smem | プロセスごとの正確な使用状況 | USS (一意セットサイズ) |
/proc/meminfo | カーネルレベルの詳細 | MemAvailable, Dirty, Slab |
よくある間違いの一つ: free 列を free -h の available 列こそが重要です。これには、カーネルがオンデマンドでキャッシュから回収できるメモリが含まれています。空きメモリが 512 MB しか表示されていなくても、利用可能メモリが 5 GB あれば、サーバーに問題はありません。
メモリが閾値を下回ると、カーネルの kswapd デーモンがバックグラウンドでページの回収を開始します。それでも不足する場合は、カーネルは直接回収モードに移行し、ページが解放されるまでプロセスをブロックします。これがレイテンシの急上昇の原因となります。 MemAvailable 総RAMの10~15%を下回ったときにアラートを設定し、対応する時間を確保してください。
スワップの設定
スワップとは、RAMが満杯になった際にカーネルが非アクティブな匿名ページを移動させるディスク領域(パーティションまたはファイル)のことです。 速度の差は顕著です。DDR4 RAMのレイテンシは約100 nsであるのに対し、NVMe SSDは約100,000 ns、SATA SSDは500,000 ns近くになります。スワップは安全のためのバッファであり、追加のRAMではありません。常にスワップに依存しているサーバーにはメモリの問題があり、スワップを増やしても解決しません。
パーティションではなくスワップファイルを使用してください。サイズ変更が容易で、パーティションの再分割も不要です。
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfileファイルを /etc/fstab に追加して、再起動後もデータを保持するようにします。 chmod 600 手順は必須です。RAMからページアウトされたデータはスワップから読み取れるため、ファイルは一般ユーザーに読み取り可能にしてはいけません。
スワップ作成後、 vm.swappinessを調整してください。デフォルトの 60 は積極的すぎます。ほとんどのホスティングワークロードでは、カーネルが RAM を優先し、スワップは最後の手段としてのみ使用するように設定するのが望ましいです:
| サーバーの役割 | vm.swappiness | vm.vfs_cache_pressure |
|---|---|---|
| 一般的なWebサーバー | 10–20 | 50 |
| データベース (MySQL/PostgreSQL) | 1~5 | 50 |
| デフォルト(ほとんどのディストリビューション) | 60 | 100 |
スワップ領域のサイズ設定について:2 GBのVPSで時折トラフィックの急増が発生する場合、1~2 GBで十分です。8 GB以上のシステムでは、通常、2~4 GBの固定スワップ領域で十分です。目的は、カーネルにコールドページ用の安全弁を提供することであり、アドレス指定可能なメモリの総量を拡張することではありません。
RAMが限られているがCPUに余裕のあるサーバーでは、zramを使用することでメモリ内に圧縮されたスワップ領域を作成し、ディスクI/Oを完全に回避できます。テナント間でNVMeが共有されるマルチテナントVPSホストでは、検討する価値があります。スワップ領域がデータベースファイルと同じデバイス上にある場合は、I/O競合に注意してください。激しいスワッピングと高スループットのディスク書き込みは、共存しにくいためです。
OOMキラー
カーネルがRAMとスワップ領域を使い果たし、他の手段で十分なメモリを解放できない場合、OOMキラーが作動します。OOMキラーは oom_badness() 関数を使用してプロセスにスコアを付けます:
points = (rss_anon + rss_file + rss_shmem + swapents + pgtables_pages) + (oom_score_adj × totalpages / 1000)スコアが最も高いプロセスが強制終了されます。この計算式はメモリを大量に消費するプロセスを優先し、カーネルは過去5秒以内にプロセスが終了したかどうかを確認することで、複数のプロセスが短時間に連続して終了するのを回避します。
ログには2種類のOOMイベントが表示されます:
- グローバル OOM — システム全体の RAM とスワップが不足している状態。ログの先頭に
Out of memory: - Cgroup OOM — コンテナまたはサービスが
memory.max制限に達しました。ログの先頭にはMemory cgroup out of memory:
過去のOOMイベントを確認するには:
dmesg -T | grep -i "out of memory"
journalctl -k --grep="oom"OOMログ内の order フィールドに注目してください。値が0より大きい場合は、メモリが完全に枯渇したのではなく、メモリの断片化が発生していることを示唆しています。つまり、空きメモリがあるにもかかわらず、カーネルが十分な連続したページを見つけられなかったということです。
OOMキラーがどのプロセスをターゲットにするかは、 /proc/<pid>/oom_score_adj。範囲は -1000(決して終了させない)から +1000(最優先で終了させる)です。systemd で管理されるサービスの場合、ユニットファイルでこれを永続的に設定します:
[Service]
OOMScoreAdjust=-1000OOMの挙動を調整するための追加のsysctlパラメータ:
| パラメータ | 値 | 効果 |
|---|---|---|
vm.overcommit_memory | 0 | デフォルトのヒューリスティック・オーバーコミットモード |
vm.overcommit_memory | 2 | 厳格モード。RAM × overcommit_ratio + swap を超える割り当てを防止 |
vm.panic_on_oom | 1 | プロセスを強制終了する代わりに再起動する |
vm.oom_kill_allocating_task | 1 | 最大のメモリ消費プロセスではなく、OOMを引き起こしたプロセスを強制終了する |
予防的な監視を行うには、 /proc/pressure/memory (Pressure Stall Information、カーネル 4.20 以降で利用可能)。 some avg10 値に注意してください。5%以下であれば正常ですが、20%以上で持続している場合は、OOMイベントが発生する可能性が高いことを意味します。 allocstall カウンターの /proc/vmstat のカウンター値が上昇していることも、もう一つの早期の兆候です。これは、OOMによるプロセス強制終了にしばしば先行する、直接的なメモリ回収のストール回数をカウントしています。 systemd-oomd や earlyoom のようなツールは、カーネルのOOMキラーが作動する前に、PSIのしきい値に基づいて動作させることができます。
cgroups とメモリ制限
コントロールグループ(cgroups)を使用すると、プロセスをグループに整理し、リソースの厳格な制限を適用できます。 Linux 2.6.24で導入されたcgroupsは、Docker、Podman、Kubernetes、LXCなどのコンテナランタイムの基盤となっています。カーネルは、匿名メモリ、ファイルベースのページ、カーネルオブジェクトを含め、cgroupごとのメモリ使用量を追跡します。cgroupが制限に達した場合、カーネルはそのグループ内のメモリを回収するか、cgroupスコープのOOMキルをトリガーします。
cgroup v1とv2の主な違いは、その構造にあります。v1では、各コントローラー(メモリ、CPU、I/O)が個別に /sys/fs/cgroup/<controller>/の下に個別にマウントするため、リソース追跡に一貫性がありません。V2は /sys/fs/cgroup/を使用します。Kubernetesはバージョン1.25でデフォルトをv2に切り替え、1.31でv1のサポートを終了しました。
お使いのシステムがどちらのバージョンを使用しているかを確認するには:
stat -fc %T /sys/fs/cgroup/cgroup2fs は v2 を意味します。 tmpfs は通常 v1 を意味します。
| 機能 | Cgroup v1 | Cgroup v2 |
|---|---|---|
| 階層 | 複数、コントローラごと | 単一、統合 |
| ハードメモリ制限 | memory.limit_in_bytes | memory.max |
| ソフトメモリ制限 | memory.soft_limit_in_bytes | memory.high (スロットリング) |
| 使用状況の追跡 | memory.usage_in_bytes | memory.current |
| プレッシャーメトリクス | 制限あり | PSI 統合 |
cgroup v2 の主要なメモリ制御:
| パラメータ | タイプ | 説明 |
|---|---|---|
memory.max | ハードリミット | これを超えると OOM キラーがトリガーされる |
memory.high | ソフトリミット | ハードリミットに達する前に、割り当てを抑制し、リクレイムをトリガーします |
memory.low | ソフト保護 | このしきい値以下のメモリは最後に回収される |
memory.min | ハード保護 | このレベル以下のメモリは決して回収されない |
memory.swap.max | スワップ制限 | 0に設定すると、このcgroupのスワップが無効になります |
memory.oom.group | ブール値 | 有効にすると、OOM が発生した際に cgroup 内のすべてのプロセスがまとめて強制終了される |
実用的なルール: memory.high ハードリミットに達する前に memory.max に設定し、ハードリミットに達する前にカーネルがメモリを回収できる余地を確保します。サイズ設定の際は memory.maxサイズを設定する際は、cgroupのメモリ合計にカウントされるページキャッシュを考慮して、アプリケーションのピーク使用量より20~30%上乗せしてください。
cgroup ファイルシステムに直接書き込むのではなく、systemd 経由で cgroup を管理してください。 MemoryMax=, MemoryHigh=や MemoryMin= などのユニットファイルのディレクティブを使用して、永続的な制限を設定してください。簡単なテストを行う場合は:
systemd-run --scope -p MemoryMax=512M <command>Webサーバーのワーカープールでは、 memory.oom.group=1 を設定すると、1つのワーカーが制限を超えた場合に確実に強制終了され、孤立したプロセスが残されることはありません。データベースエンジンについては、 memory.min を設定すると、システム全体の負荷が高まった際にもバッファプールが解放されるのを防ぎます。
サーバーの役割に応じたメモリ設定
適切なメモリ設定は、サーバーの用途によって異なります。データベースサーバーとPHPウェブサーバーに同じ設定を適用すると、どちらかのパフォーマンスに悪影響を及ぼします。
| サーバーの役割 | vm.swappiness | OOM 戦略 | Cgroupポリシー |
|---|---|---|---|
| データベース | 1–5 | 保護 (OOMScoreAdjust=-900) | 使用 memory.min バッファプールを保護するために使用 |
| Web/アプリサーバー | 10–20 | デフォルト | ワーカープールごとの上限( memory.max |
| バックグラウンドワーカー | 60 | 強制終了可能 (OOMScoreAdjust=+200) | スロットリング memory.high |
| マルチテナントVPS | 60 (zram使用時) | デフォルト | テナントごとのハードアイソレーション( memory.max |
MySQLおよびPostgreSQLの場合、利用可能なRAMの50~70%を割り当て innodb_buffer_pool_sizeに割り当て、レイテンシの急上昇を抑えるためにTransparent Huge Pagesを無効にし、systemdユニットファイル内の OOMScoreAdjust=-900 で保護してください。
PHP-FPM については、実際のメモリ使用量に基づいてワーカープールのサイズを決定してください。各ワーカーは通常 30~100 MB を使用します。割り当てられた RAM を平均ワーカーサイズで割ることで、安全な pm.max_children 値が得られます。cgroups 内の memory.max を使用してプールの上限を設定してください。
書き込み負荷の高いワークロードでは、 vm.dirty_ratio を約10%に設定し、 vm.dirty_background_ratio を3%に設定してください。これにより、ダーティページがより頻繁にフラッシュされ、大規模なI/Oストールが回避されます。
カーネルのチューニング設定を永続化するには、パラメータを /etc/sysctl.d/90-memory.confに保存することで、カーネルのチューニングを永続化してください。実行時に適用された設定は、再起動時に失われます。
役割ごとの推奨値の概要:
| パラメータ | Web/アプリケーションサーバー | データベースサーバー |
|---|---|---|
vm.swappiness | 10–20 | 1~5 |
vm.vfs_cache_pressure | 50 | 50 |
vm.dirty_ratio | 15% | 10% |
vm.min_free_kbytes | 65536 | 65536 |
| OOM保護 | デフォルト | OOMScoreAdjust=-1000 |
高密度なワークロードを実行しており、これらのポリシーを適切に適用するための余裕があるサーバーが必要な場合は、FDCの専用サーバーをご検討ください。

Linuxのメモリ管理:スワップ、OOMキラー、Cグループ
Linuxスワップ、OOMキラー、cgroupsがどのように連携するか - データベース、ウェブサーバー、マルチテナントVPSホストの設定例付き。
12分で読めます - 2026年5月31日
Prometheusとnode_exporterのセットアップガイド
15分で読めます - 2026年5月29日

ご質問またはカスタムソリューションが必要ですか?
柔軟なオプション
グローバル・リーチ
即時展開
柔軟なオプション
グローバル・リーチ
即時展開