Claude Media
Claude Codeがvm.overcommit_memory=2でOOMになる原因と設定

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 claude

1つ目で 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を使い続けるかどうか

モード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/meminfo

vm.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/meminfo

SwapTotal と 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で確かめられます。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. github.com/anthropics/claude-code/issues/92422
  2. docs.kernel.org/mm/overcommit-accounting.html
  3. code.claude.com/docs/en/troubleshooting
  4. code.claude.com/docs/en/tools-reference
この記事を共有:XはてブLinkedIn