Linux のメモリオーバーコミット: overcommit_memory の 0・1・2 と CommitLimit の読み方
Linux がメモリ確保の要求をどこまで厳しく判定するかを決める vm.overcommit_memory の 3 つのモード、/proc/meminfo の CommitLimit と Committed_AS の読み方、モード 2 に切り替える前に確認する点をカーネルドキュメントに沿って整理します。
Linux では、メモリの確保が成功しても、後でそのメモリを実際に使うときに問題が起きないことまでは、デフォルトでは保証されていません。確保の要求をどこまで厳しく判定するかは vm.overcommit_memory の設定で決まります。この記事では 3 つのカーネルドキュメント、Overcommit Accounting、/proc/sys/vm のドキュメント、/proc ファイルシステムのドキュメント をもとに、3 つのモードの違いと /proc/meminfo の CommitLimit、Committed_AS の読み方をまとめます。
3 つのモード
現在の値は次のコマンドで確認できます。
cat /proc/sys/vm/overcommit_memory
| 値 | ドキュメントでの名前 | 動作 |
|---|---|---|
0(既定値) |
ヒューリスティックなオーバーコミット | 要求サイズを全メモリとスワップの合計と比べ、明らかなオーバーコミットだけを拒否します。極端に大きな確保は失敗させ、それ以外のオーバーコミットは許してスワップの使用を減らします。 |
1 |
常にオーバーコミット | 実際にメモリが尽きるまで、メモリが常に足りているかのように動作します。 |
2 |
オーバーコミットしない | システム全体のコミット総量が、スワップと物理 RAM の一定割合(既定は 50%)の合計を超えないようにします。 |
ドキュメントは、モード 1 が向いている例として一部の科学計算コードを挙げています。疎な配列を使い、仮想メモリのほとんどがゼロページのままであることを前提にしたコードです。モード 2 は、すべてのページを事前に初期化しなくても、確保したメモリを将来使えることを保証したいアプリケーションに有用だと説明しています。オーバーコミットそのものが役に立つ理由として、/proc/sys/vm のドキュメントは「念のため」に大量のメモリを malloc() しておきながら、ほとんど使わないプログラムが多いことを挙げています。
モード 0 が何を「明らかな」オーバーコミットとみなすか、といった詳細はドキュメントには書かれていません。/proc/sys/vm のドキュメントは詳しい情報としてカーネルソース mm/util.c の __vm_enough_memory() を示していますが、この記事ではそのソースまでは扱いません。
CommitLimit: モード 2 で守られる上限
/proc/meminfo の CommitLimit は現在のコミット上限で、Committed_AS はこれまでにコミットされた量です。/proc のドキュメントに書かれた CommitLimit の式は次のとおりです。
CommitLimit = ([RAM の総ページ数] − [huge TLB の総ページ数]) × overcommit_ratio / 100 + [スワップの総ページ数]
ドキュメントの例では、物理 RAM が 1G、スワップが 7G、vm.overcommit_ratio が 30 のとき、CommitLimit は 7.3G になります。1G の 30% である 0.3G にスワップの 7G を足した値です。
割合ではなく絶対量で決めたい場合は vm.overcommit_kbytes を使います。このときコミット総量は、スワップにこの値の分の物理 RAM を足した量を超えられません。2 つの設定は同時には使えず、一方を設定するともう一方は無効になり、読むと 0 になります。
ここで見落としやすい点があります。CommitLimit の値は /proc/meminfo に常に表示されますが、この上限が実際に守られるのはモード 2 だけです。overcommit_ratio と overcommit_kbytes もモード 2 でしか効果がありません。そのため、モード 0 や 1 のシステムで Committed_AS が CommitLimit より大きくても、それだけで設定がおかしいとは言えません。この最後の文は、「モード 2 でのみ守られる」というドキュメントの説明からこの記事が導いた解釈です。
Committed_AS は実際の使用量ではなく約束した量
Committed_AS はプロセスが確保したメモリの合計で、まだ実際には使っていない部分も含みます。/proc のドキュメントの例では、1G を malloc() してそのうち 300M しか触れていないプロセスは 1G として数えられます。その 1G は、確保したアプリケーションがいつでも使えるように VM が「コミット」、つまり約束したメモリだからです。
どのマッピングがいくらとして数えられるかは、Overcommit Accounting ドキュメントの規則に従います。
| マッピング | 計上されるコスト |
|---|---|
| ファイルマッピング、SHARED または読み取り専用 | 0(マッピングの裏付けはスワップではなくファイル) |
| ファイルマッピング、PRIVATE かつ書き込み可能 | インスタンスごとにマッピングのサイズ |
匿名または /dev/zero のマッピング、SHARED |
マッピングのサイズ |
匿名または /dev/zero のマッピング、PRIVATE かつ読み取り専用 |
0(ただしほとんど役に立たない) |
匿名または /dev/zero のマッピング、PRIVATE かつ書き込み可能 |
インスタンスごとにマッピングのサイズ |
このほか、mmap によって書き込み可能なコピーになったページと shmfs のメモリも同じプールから計上されます。ドキュメントの状況一覧には、mmap のマッピング、mprotect による変化、mremap によるサイズの変化、brk、munmap を計上すると書かれており、ptrace のページの計上はまだ To Do として残っています。
自分のシステムの値を確認する
grep -E '^(MemTotal|SwapTotal|CommitLimit|Committed_AS|HugePages_Total):' /proc/meminfo
cat /proc/sys/vm/overcommit_ratio /proc/sys/vm/overcommit_kbytes
/proc のドキュメントに載っている出力例を、この方法で照らし合わせてみます。出力例には次の値があります。
MemTotal: 32858820 kB
SwapTotal: 0 kB
CommitLimit: 16429408 kB
Committed_AS: 7715148 kB
HugePages_Total: 0
出力例には overcommit_ratio の値が載っていないので、既定値の 50 と仮定します。スワップが 0 なら MemTotal の半分は 16,429,410 kB で、実際の CommitLimit は 16,429,408 kB と 2 kB の差があります。式はページ単位で定義されていて、ドキュメントはこの差を説明していません。そのため MemTotal を使った計算は、おおよその値を確かめる用途にとどめるのが安全です。同じ出力例では、Committed_AS(約 7.7GB)は CommitLimit(約 16.4GB)を下回っています。
HugePages_Total も一緒に見たのは、式で huge TLB のページを差し引いているからです。この値が 0 でなければ、その分を考慮する必要があります。hugetlb 関連の項目の詳しい意味は、この記事が参照したドキュメントの範囲外です。
どこで失敗するか
モード 2 では、ほとんどの場合、プロセスがページにアクセスしている最中に強制終了されるのではなく、メモリを確保する時点でエラーを受け取る、とドキュメントは説明しています。ただし「ほとんどの場合」という但し書きがあり、ドキュメントの注意点(Gotchas)には次の 2 つが書かれています。
- C 言語のスタックの伸長は暗黙の mremap です。絶対的な保証が必要で、限界に近い状態で運用するなら、必要と思われる最大サイズでスタックを mmap しておく必要があります。一般的なスタックの使い方では大きな問題にはなりません。
- モード 2 では
MAP_NORESERVEフラグは無視されます。
モード 1 は、実際にメモリが尽きるまで失敗を先送りします。モード 0 は、前述のヒューリスティックで明らかなオーバーコミットと判断すれば、それより早い確保の時点で要求を拒否することがあります。実際に OOM が起きた場合、/proc/sys/vm の次の 2 つの設定は、カーネルパニックを起こすかどうかと、終了させるタスクの選び方に影響します。
panic_on_oom: 既定値の 0 では、カーネルが問題のあるプロセスを選んで強制終了します(OOM killer)。1 や 2 にするとカーネルパニックを起こします。1 の場合、mempolicy や cpuset で使用ノードを制限されたプロセスがそのノードのメモリを使い切ったときは、パニックせず OOM killer がプロセスを終了させることがあります。2 では memory cgroup 内の OOM でもシステム全体がパニックします。oom_kill_allocating_task: 既定値の 0 では、OOM killer がタスク一覧全体を走査し、ヒューリスティックで終了させるタスクを選びます。0 以外なら、メモリ不足を引き起こしたタスクをそのまま終了させ、一覧の走査コストを避けます。panic_on_oomが設定されていれば、そちらが優先されます。
モード 2 に切り替える前に確認すること
まず上限がいくらになるか計算してみてください。説明用の仮の例として、RAM 16GiB、スワップなし、huge TLB ページなしのサーバーで overcommit_ratio が既定値の 50 なら、CommitLimit は約 8GiB です。モード 2 では、実際の使用量とは関係なく、コミット総量がこの値を超える確保は拒否されます。割合が 50 で huge TLB ページがなければ、スワップが RAM の半分より小さいとき上限が RAM のサイズより小さくなることも、式から直接わかります。
次に、2 つの予約分を確認します。
user_reserve_kbytes: モード 2 で、現在のプロセスサイズの 3% とこの値のうち小さいほうの空きメモリを予約しておきます。ユーザーがメモリを占有するプロセスを 1 つ起動し、そのプロセスを終了させることもできなくなる状況を防ぐための値です。既定値は min(現在のプロセスサイズの 3%, 128MB) で、モード 0 と 1 では効果がありません。0 まで減らすと、1 つのプロセスがadmin_reserve_kbytesを除くすべての空きメモリを確保でき、その後コマンドを実行しようとすると “fork: Cannot allocate memory” になります。admin_reserve_kbytes:cap_sys_admin権限を持つユーザーのために残しておく空きメモリです。既定値は min(空きページの 3%, 8MB) で、既定のヒューリスティックモードで管理者がログインしてプロセスを終了させられる程度を意図した値です。ドキュメントは、モード 2 のシステムでは復旧に使うプログラムの仮想メモリサイズ全体を考慮してこの値を増やすべきで、そうしないと root がログインできなくなるおそれがあると警告しています。ドキュメントが挙げる x86_64 での目安は、sshd や login、シェル、top などのツールを合わせて、ヒューリスティックモードで約 8MB、モード 2 で約 128MB です。
どちらの値も、変更するとアプリケーションがメモリを要求した時点から適用されます。/proc のドキュメントは、カーネルパラメータを本番システムで直接変更せず、まず開発用のマシンで試すよう勧めています。
誰が終了させられるか: oom_score_adj
OOM killer がどのプロセスを選ぶかは、プロセスごとの /proc/<pid>/oom_score_adj で調整できます。指定できる範囲は -1000 から +1000 で、この値が badness スコアに加算されてから終了対象が決まります。-1000 は、そのタスクの OOM による終了を無効にするのと同じ値です。/proc/<pid>/oom_score は現在のスコアを示し、oom_score_adj が反映されているため、実質的に 0 から 2000 の範囲の値になります。CAP_SYS_RESOURCE を持つプロセスが最後に設定した値より低くするには、CAP_SYS_RESOURCE が必要です。
この記事の範囲と限界
- この記事は 2026-10-12 に確認した docs.kernel.org のドキュメント(7.3.0-rc6 ビルド)に基づいています。/proc/sys/vm のドキュメントの冒頭には「Linux 2.6.29 で有効」という古い記述が残っていますが、この記事は同じビルドに載っている現在の内容に従いました。古いカーネルでは項目や既定値が異なる可能性があります。
- ドキュメントに書かれた既定値はカーネルの既定値です。実際のシステムの値は、上のコマンドで直接確認してください。
- モード 0 の詳細な判定ロジック(
__vm_enough_memory())と、cgroup のメモリ制限に達して起きる OOM は扱っていません。後者について /proc のドキュメントは、OOM がメモリ制限によるものなら、badness の計算の基準となる「許容メモリ」はその制限値になる、とだけ説明しています。 - カーネルドキュメントは、一般的なサーバーにどのモードを使うべきかを勧めていません。モードごとの用途を説明しているだけで、この記事も推奨モードは示しません。
CommitLimit は約束できる総量の上限で、MemAvailable はスワップなしで新しいプログラムに渡せるメモリの見積もりです。2 つは別々の問いに答えています。MemAvailable の読み方は free コマンドの available の記事 で扱っています。