Claude Codeがvm.overcommit_memory=2でOOMになる原因と設定
vm.overcommit_memory=2のLinuxでClaude Codeが即座に落ちる報告の読み方です。CommitLimitの計算、sysctlでの確認、ratioの調整とモード0へ戻す判断を扱います。
vm.overcommit_memory=2 のLinuxでは、実際に使っているメモリが少なくても、Claude Codeの起動や並列ビルドがメモリ確保の失敗で止まることがあります。実使用量と「確保を約束したメモリ」が別の数字で数えられるためです。この記事では、その仕組み、手元で切り分けるコマンド、直し方の選択肢を順に扱います。
報告されている症状とその範囲
GitHubのissue #92422は、vm.overcommit_memory=2 のLinuxでClaude Codeが過剰にメモリを確保し、OOMになるという報告です。2026年9月6日に起票され、その後もオープンのままです。コメントは0件で、stale ラベルが付いています。
報告者の環境は、バージョン2.1.238、ターミナルはalacrittyベースの自作、メモリは16GBのRAMと24GBのスワップです。書かれている内容は次の3点です。
- 1セッションの実使用量はおよそ0.5GBなのに、数GBのメモリが確保されている
- 厳格モード(2)にしているのは、ハングよりも即座のクラッシュのほうが診断しやすいから
- Claudeが大量のビルドを並列に走らせると、16GB+24GBでも足りなくなる
issueには、確保量が膨らむ原因も、修正されたバージョンも書かれていません。つまり「Claude Codeのどの処理が大きな確保をしているか」は未確認です。ここから先は、モード2の仕組みから言える範囲と、手元で確かめる手順を扱います。
モード2は実使用量でなく確保の約束を数える
Linuxカーネルのovercommit accountingは、vm.overcommit_memory に3つのモードを用意しています。
| 値 | 動作 |
|---|---|
| 0 | 動作ヒューリスティック。明らかに過大な確保だけ拒否する。既定値 |
| 1 | 動作常に許可する。スパース配列を使う科学計算向け |
| 2 | 動作過剰な確保を許さない。システム全体の確保量が「スワップ+(RAMの一定割合)」を超えると拒否する |
モード2では、確保したページを実際に触るまで待たずに、確保の時点で枠が減ります。カーネルのドキュメントは、モード2のプロセスはページへのアクセス中にkillされることが基本的になく、代わりにメモリ確保のエラーを受け取ると説明しています。報告者が「クラッシュのほうが診断しやすい」と言うのは、この性質のことです。
枠の大きさは次の式で決まります。割合の既定値は50%です。
報告者の環境にこの式を当てはめると、RAM 16GBの50%が8GB、スワップが24GBで、枠は約32GBです。計算上の目安であり、実際の値は /proc/meminfo で見ます。
どの確保が枠を減らすか
カーネルのドキュメントでは、枠を消費する確保が種類別に決まっています。
- 匿名メモリや
/dev/zeroのマップは、共有ならマップの大きさ、書き込み可能なプライベートならインスタンスごとにマップの大きさだけ数える - ファイルに裏付けられたマップは、共有または読み取り専用なら0、書き込み可能なプライベートならマップの大きさを数える
- モード2では
MAP_NORESERVEフラグが無視される
最後の点が実務上は効きます。「使うかもしれない領域を、予約なしで大きく取っておく」という確保の作法は、モード0や1では実使用量しか食いませんが、モード2では全量が枠から引かれます。実使用量が0.5GBでも、数GBの確保が数セッション分重なれば、枠の消費は実使用量の何倍にもなります。
forkも同じです。カーネルのドキュメントは、forkの時点で確保を数えて検査すると書いています。書き込み可能なプライベートマップは「インスタンスごとにマップの大きさ」が引かれるため、大きなヒープを持つプロセスが子プロセスを増やすと、Committed_AS は実使用量とは無関係に積み上がります。大きなヒープを持つプロセスが子プロセスを次々に起こすビルドでは、この計上が重なります。どれだけ積み上がるかはランタイムと並列数で変わるため、Committed_AS の増え方を手元で見るのが確実です。
手元で確かめる3つのコマンド
自分の環境が当てはまるかは、次の3つで切り分けられます。
# 1. モードと割合を確認する
sysctl vm.overcommit_memory vm.overcommit_ratio vm.overcommit_kbytes
# 2. 枠と消費量を確認する(kB単位)
grep -E 'CommitLimit|Committed_AS' /proc/meminfo
# 3. Claude Codeの仮想サイズと実使用量を並べる
ps -o pid,vsz,rss,args -C claude1つ目で vm.overcommit_memory = 2 が出れば前提が合います。2つ目は Committed_AS が CommitLimit に近づいているかを見ます。近づいたまま確保が失敗しているなら、枠の枯渇が原因の有力候補です。
3つ目は補助です。VSZ は仮想サイズの合計で、カーネルの数え方では0コストの読み取り専用マップも含みます。VSZ が RSS の何倍あるかは目安にとどまり、Committed_AS の内訳そのものではありません。プロセス名が claude と一致しない環境では、pgrep -f で拾ったPIDを ps -p に渡します。
free で空きが十分あるのに失敗する場合も、同じ構図です。空きメモリはCommitLimitと別の数字で、モード2の拒否は後者で決まります。
直し方は4つある
どれを選ぶかは、モード2にしている理由で決まります。
モード2を使い続けるかどうか
枠を広げる
vm.overcommit_ratio を上げるか、スワップを増やします。厳格に数える利点は残り、枠だけが大きくなります。
モード0へ戻す
確保時点の拒否がなくなり、枯渇するとOOM killerが働きます。報告者が避けたかった「ハング」と「killされる側を選べない」問題が戻ります。
割合を上げる(モード2のまま)
次は、割合を80に上げる例です。80はあくまで例示で、物理メモリとスワップの構成に応じて選びます。
# 一時的に変更する
sudo sysctl vm.overcommit_ratio=80
# 再起動後も残す
echo 'vm.overcommit_ratio = 80' | sudo tee /etc/sysctl.d/90-overcommit.conf
sudo sysctl --system割合を上げた後は、再び CommitLimit を読んで、想定した枠になっているかを確かめます。設定ファイルが読まれたかは、再読み込みの後に値を引いて確認します。
sysctl vm.overcommit_ratio
grep CommitLimit /proc/meminfovm.overcommit_ratio = 80 が返り、CommitLimit が「スワップ+RAMの80%」に近い値へ変わっていれば反映済みです。ratioが確保の拒否に使われるのはモード2のときだけなので、1つ目のコマンドでモードも合わせて確かめます。
スワップを足して枠を広げる
スワップは割合がかからず全量が枠に入るので、ratioを上げられない場合の手になります。次はスワップファイルを8GB足す例です。8GBは例示で、空き容量に合わせて選びます。
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
grep -E 'SwapTotal|CommitLimit' /proc/meminfoSwapTotal と CommitLimit が8GB分増えていれば有効です。再起動後も使うなら /etc/fstab への登録が別途要ります。ファイルシステムによっては fallocate でスワップを作れないため、その場合は dd で作ります。
Claude Codeを使う間だけモード0に戻す
モード2は、そのマシン上のすべてのプロセスに効くシステム全体の設定です。vm.overcommit_memory はプロセス単位では切り替えられません。切り替えるなら、作業の間だけ戻すか、Claude Codeを別のホストやコンテナで動かす選択になります。
# 現在値を控えてから、モード0へ戻す
sysctl -n vm.overcommit_memory
sudo sysctl vm.overcommit_memory=0並列ビルドの量を抑える
報告者の環境が詰まるきっかけは、Claudeが大量のビルドを並列に走らせたことです。確保の総量が枠を超えるのは、並列度が上がった瞬間です。ビルドの並列数を指示で絞れば、枠に収まる確率が上がります。CLAUDE.mdに上限を書いておく形が、指示のたびに繰り返さずに済みます。
ビルドやテストを並列で走らせるときは、make -j4 のように並列数を4以下に抑える。
npm や pnpm のスクリプトでも、並列度を指定できるものは4以下にする。4は例示で、手元で Committed_AS を見ながら調整します。ただし、これはissueの内容から導いた回避の方向で、効果を確認した報告があるわけではありません。
診断をClaude Codeに任せるときの権限
確認用のコマンドは読み取りだけで済みます。Claude Codeに切り分けを手伝わせるなら、書き込みを伴う sysctl -w や sudo を許可せず、読み取りだけを許可する形にできます。次は .claude/settings.json に置く許可ルールの例です。
{
"permissions": {
"allow": [
"Bash(sysctl vm.overcommit_memory vm.overcommit_ratio vm.overcommit_kbytes)",
"Bash(grep -E 'CommitLimit|Committed_AS' /proc/meminfo)",
"Bash(ps -o pid,vsz,rss,args -C claude)"
]
}
}CLAUDE.mdには、手順の順序を書いておくと再現しやすくなります。
メモリ確保の失敗を調べるときは、先に sysctl vm.overcommit_memory を読み、
2 のときだけ CommitLimit と Committed_AS を比較する。
sysctl の書き換えは提案にとどめ、実行しない。出力を読ませるときは、CommitLimit と Committed_AS の2行を貼ったうえで「枠の枯渇か、それ以外か」を判断させると、原因の絞り込みが速くなります。
ほかのメモリ問題と区別する
厳格モードに由来しない症状は、別の原因を疑います。
- 本体のヒープが膨らむ場合: Claude Codeのトラブルシューティングは、セッションのヒープが2.5GBを超えると警告が出ると説明しています。
/heapdumpは、メモリの大半がJSヒープかネイティブかを要約で示します。原因の分類はClaude Codeのメモリリークとその対処で扱っています - Bashなどの子プロセスが膨らむ場合:
CLAUDE_CODE_TOOL_MEMORY_LIMITはcgroupでBash・PowerShell・Monitorの使用量に上限をかける変数です。overcommitの枠とは別の仕組みで、使い方はツールのメモリ上限の記事にまとめています - コンテナがexit code 137で落ちる場合: killしたのが誰かを調べる手順はexit code 137のOOMを切り分ける手順にあります
- Runnerでセッション同士が巻き込まれる場合: セッション単位のメモリ上限で分離できます
持ち帰る判断
vm.overcommit_memory=2 の環境でClaude Codeが確保に失敗するなら、まず CommitLimit と Committed_AS を並べます。枠が足りないだけなら、vm.overcommit_ratio かスワップで広げるのが、厳格モードの利点を残す最短の手です。
一方、確保が膨らむ原因そのものは、issue #92422の時点では未解明です。修正版が出たかは、このissueのクローズ状況とchangelogで確かめられます。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。