OOM Killerの確認方法|Ubuntuのメモリ不足とswap追加

OOM Killerの確認方法|Ubuntuのメモリ不足とswap追加

【PR】この記事にはアフィリエイトリンク(ConoHa VPS)が含まれます。

ビルドの途中で、ターミナルに一行だけ Killed と出て止まる。深夜にサイトが500エラーになっていて、朝見たら MariaDB が落ちている。しかもエラーらしいエラーがどこにも残っていない

VPSを運用していると、この「理由を言わずに死ぬ」現象に必ず一度は出会います。犯人はたいていカーネルの OOM Killer(メモリが枯渇したときに、プロセスを強制終了してシステム全体を守る仕組み)です。

ただ、ここでいきなり swap を足したり、プランを上げたりするのは早い。同じ「勝手に落ちる」でも、ディスクが満杯で落ちているケース、systemd の設定で止まっているケース、コンテナのメモリ制限に当たっているケースがあり、対処がまったく違うからです。まずは証拠を取ります。

この記事の結論(まずこの3コマンド)
# ① OOMの証拠を探す(いま起動しているブートのカーネルログ)
sudo journalctl -k -g "out of memory" --no-pager

# ② 落ちた後に再起動している場合は、1つ前のブートも見る(★これを忘れると空振りする)
sudo journalctl -k -b -1 -g "out of memory" --no-pager

# ③ いまのメモリの余裕を見る(見るのは free ではなく available)
free -h
  • Out of memory: Killed process ... が出たらOOM確定。出なければ犯人はメモリではないので、この記事の後半(swap・増強)に進んではいけません
  • free -hfree が少ないのは正常。判断に使うのは available の列です
  • swapは延命であって解決ではない。落ちるのを止める効果は大きいが、常時swapを使っている状態は「メモリが足りていない」というサイン
  • 増やす前にやれることがある:PHP-FPMの子プロセス数、MariaDBのバッファ、Nodeのヒープ上限、ビルドの並列数
  • それでもダメなら増やす。ただし増強には条件があり、判断基準と各社の制約は記事の後半にまとめています

この記事では、証拠を取る → free -h を正しく読む → swapで延命する → どこで諦めて増強するかの順に書きます。動作確認は Ubuntu 24.04 LTS の実機と、26.04(resolute)のマニュアル・パッケージ構成で行いました(2026年8月25日時点)。

なお、契約前に「どのプランを選ぶか」で迷っている場合はこの記事ではありません。用途別のメモリ目安はVPSスペックの選び方|メモリは何GB必要?が担当しています。この記事はすでに動いているサーバーが足りなくなった後の話です。

OOM Killerの確認フロー図。journalctl -k でOut of memoryのログを探し、見つかればOOM確定、見つからなければディスク満杯やsystemdの停止など別の原因を疑う
「勝手に落ちた」の原因がメモリかどうかは、カーネルログを見れば5秒で分かる
目次

まず「本当にOOM Killerだったのか」を証拠で確かめる

OOM Killer は、システム全体のメモリが尽きたときにカーネルが発動させる最終手段です。いま一番メモリを使っている(正確には、殺したときに最も効果が大きいとカーネルが判断した)プロセスを選んで SIGKILL で強制終了します。

SIGKILL はプロセス側で捕まえられません。だから、落とされた側のアプリケーションログにはきれいに何も残らないことが多いのです。「ログが無いから原因不明」ではなく、探す場所がアプリのログではなくカーネルのログ、というだけです。

Killed の一行は、シェルが出しているメッセージ

ターミナルで npm run build を叩いて、次のように出て止まったとします。

$ npm run build
...
Killed

この Killed は npm でも Node でもなく、シェル(bash)が「子プロセスが SIGKILL で終了しました」と報告している一行です。だから詳細が何も書かれていません。終了コードは 128 + 9 = 137 になります。

echo $?      # 直前のコマンドの終了コード。137 なら SIGKILL で殺されている

137 を見た時点でOOMの可能性は高いのですが、SIGKILL は人間や他のプロセスからも送れるので、これだけでは確定しません。次でカーネルに聞きます。

カーネルログにOOMの証拠を探す

証拠はカーネルログにあります。3つの探し方を用意しておくと、たいていのケースで見つかります。

# ① いま起動中のブートから探す
sudo journalctl -k -g "out of memory" --no-pager

# ② 期間で横断的に探す
# ★ -b all を必ず付ける。付けないと -k が今回のブートに固定され、--since を書いても過去ブートを見ない
# ※ -g のパターンをすべて小文字にすると大文字小文字を区別せずに検索される
sudo journalctl -k -b all --since "7 days ago" -g "out of memory|oom-kill|killed process" --no-pager

# ③ ブートの一覧を見て、落ちた回を特定してから見る
journalctl --list-boots
sudo journalctl -k -b -1 -g "out of memory" --no-pager
⚠️ ハマりどころ:journalctl -k だけで「OOMは起きていない」と判断してはいけない

-k--dmesg)は --boot=0 を含意します(man journalctl(1) に明記)。つまりいま起動しているブートのカーネルログしか見ません

OOMでサーバーが不安定になり、再起動して復旧した——という一番よくある流れだと、復旧後に journalctl -k を叩いても何も出ません。「ログに何も無いからOOMではない」と読み違えるのはここです。

落ちた後に再起動しているなら、必ず -b -1(1つ前のブート)を見てください。 どのブートで落ちたか分からないときは journalctl --list-boots で一覧を出し、時刻から当たりを付けます。

もう1つ、dmesg で見ようとして権限に阻まれることがあります。

dmesg | grep -i "out of memory"
# dmesg: read kernel buffer failed: Operation not permitted

Ubuntu は 20.10 以降 kernel.dmesg_restrict が既定で有効(Ubuntu Security/Features に記載)なので、一般ユーザーでは dmesg が読めません。sudo dmesg -T | grep -i "out of memory" のように sudo を付けるのが正解です(-T で時刻が人間に読める形式になります)。

出てきたログの読み方

OOM Killer が発動すると、カーネルログにはひとかたまりのログが出ます。実際に見るべきは次の3行です(数値は例)。

[12345.678901] npm invoked oom-killer: gfp_mask=0x140cca(GFP_HIGHUSER_MOVABLE|__GFP_COMP), order=0, oom_score_adj=0
[12345.679012] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/,task=node,pid=1234,uid=1000
[12345.679100] Out of memory: Killed process 1234 (node) total-vm:2841232kB, anon-rss:812444kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:2160kB oom_score_adj:0
… invoked oom-killer:

メモリを要求して足りなくなった側のプロセス名です。ここに出るプロセスと、実際に殺されたプロセスは別物であることが多い(例:npm が要求したせいで、一番太っていた MariaDB が殺される)。犯人捜しをここで終わらせないでください。

oom-kill:constraint=…

どういう文脈で発動したかです。見るのは global_oomoom_memcg=の1点だけ。global_oom ならシステム全体のメモリ枯渇oom_memcg=/system.slice/… と出ていれば、そのcgroupに掛けたメモリ上限に当たっています(このとき3行目も Out of memory: ではなく Memory cgroup out of memory: になります)。

⚠️ task_memcg= を判別に使わないでください。これは「殺されたプロセスがどのcgroupに居たか」を示すだけで、グローバルOOMでも必ず出ます。systemd 配下のサービスが殺されれば、単なるメモリ枯渇でも task_memcg=/system.slice/mariadb.service と表示されます。ここを根拠に判断すると、存在しない MemoryMax を探しに行くことになります。

Out of memory: Killed process 1234 (node) …

実際に殺されたプロセスです。(…) の中がプロセス名。anon-rss は、そのプロセスが抱えていた匿名メモリ(ヒープなど)の量です。上の例なら約812MB。ファイルキャッシュと違って捨てて済ませることができないメモリなので、swapが無ければメモリ上に居座り続けます(swapがあれば、ここが退避先に流れます)。

この3行が揃っていれば、メモリ不足で落ちたことは確定です。あとは「誰が要求して、誰が殺されたか」を押さえて次に進みます。

証拠が無いなら、犯人はメモリではない

逆に、期間を広げて探しても Out of memory が1件も出てこないなら、それはOOMではありません。ここで swap を足しても直りませんし、プランを上げてもお金が減るだけです。この場合に疑う先を挙げておきます。

  • ディスクが満杯No space left on device):ログもDBも書けなくなり、結果としてサービスが止まります。まず df -h /df -i / を見てください。切り分け手順は別記事で扱います
  • cgroup(サービス単位)のメモリ上限に当たっている:ログに Memory cgroup out of memory と出ます。システム全体には余裕があるのに、その1サービスだけが殺されている状態です
  • Docker コンテナのメモリ制限:コンテナが終了コード137で落ちます。docker inspect --format '{{.State.OOMKilled}}' <コンテナ名>true なら、原因はコンテナに掛けた上限です
  • systemd が止めているsudo journalctl -u <サービス名> -n 50 --no-pager を見ます。設定ミスで起動に失敗している、TimeoutStartSec を超えて止められている、といったケースがあります
  • 人間かスクリプトが kill している:デプロイスクリプト、cron、監視ツールなど。心当たりの無い定期的な停止は、まず cron を疑います
補足:systemd-oomd が犯人のこともある(が、Ubuntu Server の既定では入っていないことが多い)

Ubuntu には、カーネルのOOM Killerとは別に systemd-oomd(メモリ圧が高くなった時点で、手遅れになる前にcgroup単位で終了させる仕組み)があります。こちらが動いた場合、ログは Out of memory: ではなく Killed /user.slice/… due to memory pressure … のような文面になります。

Ubuntu Desktop は 22.04 以降で既定有効ですが、Ubuntu Server には既定でインストールされていないとされています(Launchpad の議論で開発者が明言。ただし提供形態は変わりうるので、自分の環境で確認するのが確実です)。

systemctl status systemd-oomd          # そもそも動いているか
sudo journalctl -u systemd-oomd -n 30 --no-pager

VPSのUbuntu Serverで「OOMのカーネルログが無いのに落ちる」なら、まずは systemd-oomd 以外(ディスク・cgroup上限・systemd)を先に疑ってください。

free -h の読み方(free が少ない=メモリ不足、ではない)

OOMが確定したら、次はいまどれくらい余裕が無いのかを見ます。ここで多くの人が読み違えるので、丁寧に書きます。

free -h
               total        used        free      shared  buff/cache   available
Mem:           956Mi       612Mi        84Mi        12Mi       380Mi       344Mi
Swap:          2.0Gi       128Mi       1.9Gi

この出力を見て「空きが84Miしかないからメモリがギリギリだ」と判断してしまうのが典型的な誤読です。Linuxは空いているメモリをファイルキャッシュとして使い切るのが正常な状態で、free(どこにも使われていないメモリ)は少なくて当たり前です。

見るのは available の列だけ

procps-ng の man(free(1))は各列を次のように定義しています。

free

まったく使われていないメモリ(/proc/meminfo の MemFree)。少なくても問題ありません。

buff/cache

バッファとキャッシュの合計。必要になれば大部分がすぐ回収されるので、これは「使用中」ではなく「有効活用中」と読みます。

available

スワップせずに、新しくアプリを起動するために使えるメモリの推定値。man の表現では「page cache を考慮に入れ、かつ回収可能なslabのすべてが回収できるわけではないことも織り込んだ推定値」です。判断に使うのはこの列です。

used

man の定義は total - available。つまり「回収できないぶんのキャッシュ」も含めて、実質的に使えない量として計算されています。

上の例なら、available は 344Mi。total 956Mi に対しておよそ36%が残っている、と読みます。

free -h の読み方の図解。total 956MiBのうち used 612MiB、回収できるキャッシュ 260MiB、free 84MiBに分かれ、available 344MiB は free と回収可能キャッシュの合計であることを示す
free が84MiBでも、実際に使えるのは available の344MiB。見る列を間違えると誤診する

判断ラインは、VPSスペックの選び方と同じものを使ってください。available が total の10〜15%を常に下回るようなら、チューニングか増強の検討時期です。そして Swap 行の used が日に日に増えているなら、それは「swapで延命している」のではなく「すでにメモリが足りていない」という状態です。

何がメモリを食べているかを特定する

available が細っているなら、犯人を特定します。

# メモリ使用量の多い順に上位9プロセス(1行目はヘッダ)
ps aux --sort=-%mem | head -n 10

# RSS だけをMB単位で並べる(読みやすい)
ps -eo rss=,comm= --sort=-rss | head -n 10 | awk '{printf "%8.1f MB  %s\n", $1/1024, $2}'

ここで注意したいのが、RSS(実メモリ使用量)を単純に足し算すると実際より多く出ることです。子プロセスは親とメモリを共有しているため、共有分を二重に数えてしまいます。正確に見たいときは PSS を使います。

# 特定プロセスの PSS(共有分を按分した値)
sudo grep -E '^(Pss|Rss)' /proc/$(pgrep -o php-fpm)/smaps_rollup

多いパターンは決まっていて、上位が php-fpm ばかりか、mariadbd(または mysqld)が突出しているか、Node のビルドプロセスが一瞬で膨らむかの3つです。それぞれの対処は後述します。

落ちる前の「予兆」を見る(メモリ圧の指標)

free -h は「今この瞬間」しか見えません。落ちる前に気づきたいなら、カーネルのメモリ圧(PSI)を見る手があります。

cat /proc/pressure/memory
some avg10=0.00 avg60=0.00 avg300=0.00 total=0
full avg10=0.00 avg60=0.00 avg300=0.00 total=0

avg10(直近10秒)が常に0に近ければ、メモリ待ちは発生していません。ここが数十%に張り付いているなら、OOMで落ちる手前の状態です。カーネルの設定によってはこのファイル自体が存在しないことがあるので、無ければ諦めて free の定点観測(vmstat 60 を流しておくなど)に切り替えてください。

swapは「延命」であって解決ではない

ここまでで「メモリが足りない」ことが確定した前提で、swapの話に入ります。ただし最初に立場を明確にしておきます。swapはメモリの代わりにはなりません。

swapありとswapなしでOOM Killerの発動がどう変わるかの時系列図。swapなしはピークでプロセスがKilledされ、swapありは遅くなるが処理を完走する
swapは「落ちる」を「遅い」に変える仕組み。時間は稼げるが、足りない事実は変わらない

swapがあると、あふれた分がディスクに退避されるので、遅くはなりますが、すぐには落ちません。「止まる」と「遅い」の差は運用上とても大きく、月に数回しか起きない一瞬のピークを吸収するには十分な効果があります。

一方で、代償もはっきりしています。

  • 速度:メモリとSSDでは桁違いに遅い。swapを激しく使い始めると、サーバー全体の応答が体感で分かるほど落ちます(スワップの読み書きが止まらない状態=スラッシングになれば、実質的にサービス停止です)
  • SSDへの書き込み:swapは書き込みを伴います。常時swapを使い続ける運用は、ディスクにも優しくありません
  • 限界:swapを使い切れば、結局OOM Killerが動きます

つまりswapは「保険」です。常時swapを使っているなら、それは保険ではなくメモリ不足であり、設定を絞るか、プランを上げるかの判断に移るべき状態です。

Ubuntuでswapを追加する手順(24.04 / 26.04)

ここからは実際の手順です。本番サーバーで実行する前提で、危険な箇所には警告を入れてあります。

なお、これから初期設定をする段階なら、Ubuntu 26.04 LTSのインストールと初期設定の中でswapまで一気に済ませるほうが早いです。この記事の手順は、すでに運用しているサーバーに後から足すケース向けに、確認と安全策を厚くしたものです。

現状を確認する(すでにswapがある場合を潰す)

swapon --show     # 何も出力されなければ swap は存在しない
free -h           # Swap 行が 0B なら同上

swapon --show が何も返さなければ、swapはありません。すでに存在する場合は、新しく作るより既存のサイズを変えるほうが安全です(既存をswapoffして作り直します。後述)。

サイズを決める

小さいプランほどswapの重要度は上がります。目安はこうです。

  • メモリ2GB未満:メモリと同じ〜2倍(1GBプランなら2GB、512MBプランなら1GB)
  • メモリ4GB以上:2GB程度あれば保険として機能する

「大きければ安心」ではありません。swapを大量に使う状態は、そもそもサービスとして成立していないので、際限なく積む意味はありません。

ディスクの空きを確認する(★これを忘れて事故る)

swapファイルは、その容量ぶんディスクを消費します。2GBのswapを作るなら2GBの空きが要ります。

df -h /

Use% が90%を超えているような状態でswapを作ると、メモリ不足をディスク満杯に置き換えるだけです。ディスクが逼迫している場合は、先にそちらを片付けてください(No space left on device の切り分けは別記事で扱います)。

swapファイルを作る

# 2GB のファイルを確保する(高速)
sudo fallocate -l 2G /swapfile

# 所有者以外から読めないようにする(★必須。緩いと mkswap が警告を出す)
sudo chmod 600 /swapfile

# swap 領域として初期化する
sudo mkswap /swapfile

# 有効化する
sudo swapon /swapfile

# 確認
swapon --show
free -h

swapon --show にこう出れば成功です。

NAME      TYPE SIZE USED PRIO
/swapfile file   2G   0B   -2
⚠️ swapon failed: Invalid argument が出たら、ファイルシステムの問題

sudo swapon /swapfile が次のように失敗することがあります。

swapon: /swapfile: swapon failed: Invalid argument

man swapon(8) は、カーネルはswapファイルに「ファイルシステムを介さず直接書き込む」ことを期待しているため、穴(hole)のあるファイルや Btrfs のような CoW ファイルシステム上のファイルでは問題になると説明しています。そして fallocate で確保したファイルも、ファイルシステムによっては穴があると解釈されうること、最も確実な作成方法は dd/dev/zero から書き出すことが明記されています。

Ubuntu の既定は ext4 なので通常は fallocate で問題ありませんが、失敗したら作り直してください。

sudo rm /swapfile
# 2GB を実際に書き込む(1MiB × 2048。fallocate より時間がかかる)
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048 status=progress
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

/etc/fstab に登録して、再起動後も有効にする

ここがこの記事で唯一、書き間違えるとサーバーが起動しなくなる場所です。慎重にいきます。

# ① 先にバックアップを取る
sudo cp /etc/fstab /etc/fstab.bak.$(date +%F)

# ② 追記する(★ tee の -a を絶対に忘れない)
# ★ 先頭に改行を入れる。fstab が改行で終わっていない環境だと、最終行(多くは / の行)に連結して壊れる
printf '
/swapfile none swap sw,nofail 0 0
' | sudo tee -a /etc/fstab

# ③ 目視と機械チェックの両方をやる
cat /etc/fstab
findmnt --verify --verbose      # fstab の文法・実在性をまとめて検証する
🔴 /etc/fstab を壊すとSSHでは復旧できない(コンソールが必要になる)
  • tee -a-a(追記)を落とすと、/etc/fstab が1行だけのファイルに上書きされます。 ルートファイルシステムの行が消えるので、次の再起動で起動しません。同じ理由で、リダイレクトを使うなら >> であって > ではありません。追記したら必ず cat /etc/fstab で全文を目視してください
  • findmnt --verify を必ず通してください。swapon -a は swap 行しか見ないので、上の連結事故で壊れた / の行はこちらでないと検出できません。ここが「fstab を書き間違えて起動しなくなる」唯一の残存リスクです
  • swap行には nofail を付けるのを推奨します。man systemd.swap(5) には「nofail を付けると、そのswapユニットは swap.target から *required* ではなく *wanted* になる。これはswapデバイスの有効化に失敗してもブートが継続することを意味する」と明記されています。つまり、swapの有効化に失敗しても、起動が失敗ユニットや待ち時間で引っかからずに済みます(なお、起動そのものを止めるのは / などのマウント行の失敗です。swap行の失敗で emergency mode に落ちるわけではありません)
  • それでも壊してしまったら、SSHでは入れません。VPSのコントロールパネルのコンソール(ブラウザからサーバーの画面に直接ログインする機能)から復旧します。この復旧手段についてはVPSにSSH接続できないときの原因チェックリストに書きました

再起動する前に、fstabの記述が効くことを確認する

「書いたつもりで効いていない」「書き間違えたまま再起動して起動しなくなった」——どちらも、再起動の前にテストすれば防げます。

# ① いったんswapを外して、fstab の記述だけで戻せるかを試す
sudo swapoff /swapfile
sudo swapon -a          # ← fstab を読んで有効化する(noauto 以外のすべて)
swapon --show           # ここに /swapfile が戻ってくれば fstab の行は正しい

# ② systemd 側からも見えるか確認する
sudo systemctl daemon-reload
systemctl status swapfile.swap --no-pager

swapon -a/etc/fstabswap と記された領域を有効化するコマンドなので、これが通れば fstab の行の書式は正しいと判断できます。

2つ目のユニット名は、systemd がパスから自動生成したものです。/swapfile なら swapfile.swap になります。別のパスに置いた場合は次で確認できます。

systemd-escape -p --suffix=swap /var/swapfile     # → var-swapfile.swap

Active: active になっていれば、再起動後も同じように有効化されます。ここまで確認してから再起動してください。

vm.swappiness を下げる(が、0にはしない)

vm.swappiness は、スワップとファイルページ回収の相対的なI/Oコストをカーネルに教える値です。カーネルのドキュメントによれば 範囲は0〜200、既定値は60。VPSのように「swapは保険」という使い方なら、10前後まで下げて本当に足りないときだけ使わせるのが定石です。

# 現在値
sysctl vm.swappiness

# 永続化(再起動しても効く形で入れる)
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-zz-swappiness.conf
sudo sysctl --system
sysctl vm.swappiness      # 再起動した後にもう一度叩いて確認する
⚠️ swappiness=0 はswapの無効化ではない

vm.swappiness=0 にすれば「swapを使わなくなる」と思われがちですが、カーネルのドキュメントの表現は 「0では、ゾーン内の free とファイルバックのページ量が high watermark を下回るまで、カーネルはスワップを開始しない」です。つまりぎりぎりまで我慢するだけで、swapが無効になるわけではありません。しかも我慢しすぎるぶん、OOM Killerが動きやすくなる方向に働きます。落ちるのを防ぎたくて入れたswapなのに逆効果になるので、0にはしないでください。

また、sudo sysctl -w vm.swappiness=10 だけで済ませると再起動で60に戻ります。設定ファイルに書いてください。なお /etc/sysctl.d/ はsshdのドロップインとは逆で「辞書順で後ろに来たファイルが勝つ」仕組みです(上の例が 99-zz- で始まっているのはこのため)。この落とし穴の詳しい説明はVPSスペックの選び方に書いています。

補足:swapのサイズを変えたい/zramという選択肢(クリックで開く)

サイズを変えたいときは、いったん外してから作り直します。使用中のswapファイルに mkswap を掛けてはいけません。

sudo swapoff /swapfile
sudo rm /swapfile
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --show

swapoff は、swapに退避されていた内容をメモリに戻す動作なので、メモリが逼迫している最中に実行すると、その瞬間にOOMを誘発することがあります。サイズ変更は落ち着いているときにやってください。

zram(メモリの一部を圧縮してswap領域として使う仕組み)という選択肢もあります。ディスクに書かないぶん高速ですが、圧縮に使うぶんの物理メモリを消費するので、極端に小さいプランでは万能ではありません。Ubuntu には zram-config パッケージが用意されています(24.04・26.04 とも universe。2026年8月25日時点でパッケージ一覧にて確認)。ディスクswapとどちらが有利かはワークロード次第なので、導入するなら片方ずつ試して free -h と応答時間で比較してください。

メモリを増やす前に、やれることが3つある

swapを入れて落ちなくなったら、次にやるのはプランの変更ではなく設定の見直しです。ここを飛ばして増強すると、たいていは増やしたぶんもそのうち食い尽くします。

VPSのメモリ不足への対処を優先順位で示した図。証拠を取る、swapを足す、設定を絞る、最後にプランを上げるの4段階
上から順に。いきなり一番下(増強)に行かないのがコツ

① 常駐プロセスの上限を絞る

WordPress構成なら、まず PHP-FPM の子プロセス数と MariaDB のバッファです。

# PHP-FPM:いまの設定と、実際の子プロセスのRSSを見る
grep -E "^pm|max_children" /etc/php/*/fpm/pool.d/www.conf
ps -o rss=,cmd= -C php-fpm8.3

# MariaDB:バッファプールの現在値を見る
sudo mariadb -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"

危険なのは「子プロセスが増えすぎること」そのものではなく、pm.max_children × 子1つあたりのメモリが、物理メモリを超える値に設定されている状態です。アクセスが増えた瞬間にOOMまで届きます。小さいプランなら pm = ondemand にして max_children を絞るのが定石です(絞りすぎると今度は503側に倒れるので、ps で実測しながら調整してください)。詳しい考え方はVPSスペックの選び方に書きました。

② ビルド・バッチ側の使用量を抑える

「サイトは普通に動くのに、ビルドのときだけ落ちる」なら、恒久的にメモリを増やす必要はないかもしれません。

# Node:V8 のヒープ上限を明示する(プランのメモリより十分小さい値に)
NODE_OPTIONS=--max-old-space-size=1024 npm run build

# 並列数を絞る(メモリのピークは並列数にほぼ比例する)
make -j2                      # nproc の値をそのまま使わない

私自身、当サイトの /tools/(Quasar+Vite)を型チェック込みでビルドすると、ローカルPCでも数GBを使います。小さいVPS上で同じことをやれば当然落ちます。 現実的な解として、ビルドは手元やCIで済ませて、成果物だけをサーバーに転送する構成に変えてしまうのも有力です(この方法なら費用は増えません)。

③ 落としたくないプロセスを守る

OOM Killerがどれを殺すかは、oom_score_adj の値で調整できます。MariaDBだけは死守したいなら、systemd のドロップインで下駄を履かせます。

sudo systemctl edit mariadb
# [Service]
# OOMScoreAdjust=-500

sudo systemctl daemon-reload
sudo systemctl restart mariadb
systemctl show mariadb -p OOMScoreAdjust     # ← 反映確認。OOMScoreAdjust=-500 と出れば効いている

ただしこれは「代わりに別のプロセスが殺される」だけで、メモリ不足そのものは解決しません。優先順位を決める道具として使ってください。

どこで諦めてメモリを増やすか

ここまで全部やってもダメなら、増やすしかありません。私が線を引いているのは次の3つが揃ったときです。

available が常に total の10〜15%を下回る

一時的なピークではなく、平常時からこの状態なら足りていません。

swapを常時使っている

free -hSwapused が、再起動後から単調に増えていく状態。保険ではなく常用になっています。

設定を絞ると、機能として成り立たなくなる

pm.max_children を減らすと503が出る、バッファを削るとDBが遅すぎる——ここまで来ると、チューニングではなく容量の問題です。

この判断は、契約前のスペック選びと表裏一体です。どのクラスに上げるべきか、そもそも上げられる契約なのかは、次の記事に用途別の目安と各社の制約(上げられない最小プランがある、下げる方向には制限がある、など)をまとめてあります。

ConoHa VPS の「一時的に上げて戻す」は使えるか(停止が必要/512MBは対象外)

私が使っている ConoHa VPS の場合、公式サイトには料金タイプが2種類あり、そのうち「時間課金」タイプについて 「1時間単位課金なので、使った分だけのお支払い」 と記載されています(2026年8月25日確認)。長期割引の「まとめトク」(旧・VPS割引きっぷ)は一括前払いで、途中解約を承ることはできないと明記されているので、まとめトクで契約している場合はこの「上げて戻す」のコスト計算がそのままは当てはまりません。これが効いてくるのが、恒常的には足りているが、月に数回のビルドやデータ移行のときだけ足りないというケースです。

作業の間だけ上位プランに上げて、終わったら戻す。これができるかどうかは契約している会社の仕様次第なので、私が実際に確認した ConoHa VPS の仕様を書いておきます(いずれも公式ページで2026年8月25日に確認)。

上げたあと戻せる

公式のスケールアップ・ダウン機能のページに「最初に選択したサーバーのスペックでは足りないと感じたら、すぐに上位プランへ変更したり、戻したりでき、結果としてコストの最適化が出来ます」と記載されています。

プラン変更にはサーバーの停止が必要

サポートページに「スペックを変更できるのは停止しているVPSのみです」と明記。つまり上げるときと戻すときの2回、ダウンタイムが発生します。公開サービスを載せているなら、アクセスの少ない時間帯に行ってください。

512MBプランは対象外

「512MBプランではスケールアップ・ダウン機能をご利用いただけません」と公式に記載されています。最小プランを選ぶと、この「一時的に上げる」戦法自体が使えません。

割引きっぷを使っている場合は連動する

サポートページに「VPS割引きっぷが設定されている場合、VPSと連動してVPS割引きっぷもプラン変更されます」と記載があります。長期割引を適用中なら、短期の上げ下げを試す前に条件を確認してください。

料金の具体額と課金の計算方法は改定されるので、申し込み・変更の前に必ず公式サイトで最新の条件を確認してください。この記事では金額を書きません(各社のプラン構成と料金の横並びはVPS比較2026|個人向けおすすめ4社が担当しています)。

【PR】以下は ConoHa VPS の広告リンクです。料金・プラン変更の条件は公式サイトでご確認ください。

なお、増強分の費用は事業で使う範囲で経費に計上できます(家事按分が必要な場合があります)。経費が増えたときに手取りがどう動くかは試算できるので、必要だと判断できたなら、増強も選択肢です(逆に、使っていないリソースに払い続けても手取りが減るだけです)。

勘定科目や家事按分の考え方はサーバー代・レンタルサーバー代の勘定科目と経費計上にまとめています。税額・控除の扱いは条件によって変わるので、最終的な判断は最新の情報(国税庁など)と、必要に応じて税理士への確認をおすすめします。

次に読む記事

この記事は「もう落ちてしまった後」の診断と対処が担当です。前後の内容は別記事に分けてあります。

まとめ

OOM Killerで落ちたときの手順(保存版)
  1. 証拠を取るsudo journalctl -k -g "out of memory"再起動しているなら -b -1 も見る-k は今回のブートしか見ない)
  2. ログを読むinvoked oom-killer=要求した側、Out of memory: Killed process=殺された側。別プロセスであることが多い
  3. 証拠が無ければOOMではない:ディスク満杯・cgroup上限・systemd・コンテナの制限を疑う。swapを足しても直らない
  4. free -havailable だけ見るfree が少ないのは正常。total の10〜15%を常に下回るなら足りていない
  5. swapを足すfallocatechmod 600mkswapswapon/etc/fstabnofail 付きで追記。再起動する前に swapon -a で検証する
  6. vm.swappiness は10前後。0にしてはいけない(swapの無効化ではなく、OOMが起きやすくなる)
  7. 増やす前に設定を絞るpm.max_childreninnodb_buffer_pool_size、Nodeのヒープ上限、ビルドの並列数
  8. それでも足りなければ増強。時間単位課金なら「作業の間だけ上げて戻す」も選択肢(プラン変更にはダウンタイムが伴う)

OOMの厄介さは、落ちた側のログに何も残らないことに尽きます。逆に言えば、カーネルログの見方さえ知っていれば、原因の特定は数分で終わります。そして原因さえ分かれば、対処の多くは無料でできることばかりです。

私も1GBプランで何度も MariaDB を落としました。慌ててプランを上げる前に、まず journalctl -k を叩く——それだけで、無駄な出費と無駄な調査時間の両方が減ります。

【PR】以下は ConoHa VPS の広告リンクです。

ConoHa VPS のプラン・スケールアップの条件を公式サイトで確認する
OOM Killerが動いたかどうかは、どうやって確認しますか?

カーネルログを見ます。sudo journalctl -k -g "out of memory" --no-pager を実行して、Out of memory: Killed process 1234 (プロセス名) という行が出ればOOM Killerが発動しています。注意点として、journalctl-k オプションは --boot=0(今回のブート)を含意するため、落ちた後にサーバーを再起動していると何も出ません。その場合は sudo journalctl -k -b -1 -g "out of memory" で1つ前のブートを見てください。dmesg で見る場合は、Ubuntu 20.10 以降 kernel.dmesg_restrict が既定で有効なため sudo dmesg -T のように sudo が必要です。ログが1件も見つからないなら原因はメモリではないので、ディスクの空き(df -h / df -i)やコンテナのメモリ制限を疑ってください。

swapを追加すれば、メモリ不足は解決しますか?

解決ではなく延命です。swapがあると、あふれたぶんがディスクに退避されるので、一瞬のピークでプロセスが強制終了されるのを防げます。「止まる」が「遅くなる」に変わるので運用上の効果は大きいのですが、swapを使い切れば結局OOM Killerが動きますし、常時swapを使っている状態は「メモリが足りていない」というサインです。目安として、メモリ2GB未満のプランならメモリと同じ〜2倍、4GB以上なら2GB程度を保険として確保し、vm.swappiness は10前後に下げて「本当に足りないときだけ使う」設定にしておくのがおすすめです。恒常的に足りないなら、設定を絞るかプランを上げる判断に移ってください。

free -h の free がほとんど残っていません。メモリ不足ですか?

その可能性は低いです。Linuxは空いているメモリをファイルキャッシュとして活用するので、free(どこにも使われていないメモリ)が少ないのは正常な状態です。判断に使うのは available の列で、これは「スワップせずに新しくアプリを起動するために使えるメモリの推定値」です(procps-ng の man free(1) の定義)。available が total の20%以上あれば余裕あり、10〜15%を常に下回るならチューニングか増強の検討時期、Swapused が増え続けているならすでに足りていない、という読み方をします。

ビルドのときだけ Killed されます。プランを上げるしかないですか?

いいえ、先に試すことがあります。まずビルド側の使用量を抑える方法として、Node なら NODE_OPTIONS=--max-old-space-size=1024 でヒープ上限を明示する、make -j2 のように並列数を絞る、といった手があります。もっと確実なのは、ビルドを手元のPCやCIで実行して、成果物だけをサーバーに転送する構成に変えることです。これなら費用は増えません。それでもサーバー上でビルドする必要があるなら、時間単位課金のあるVPSなら「作業の間だけ上位プランに変更して、終わったら戻す」という方法があります。ただしプラン変更にはサーバーの停止が必要な場合が多く、上げるとき・戻すときの2回ダウンタイムが発生します。契約中のプランが変更対象かどうか(最小プランは対象外の会社があります)も含めて、事前に公式サイトで確認してください。


出典(すべて 2026年8月25日 確認)

  • Linux カーネル ドキュメント admin-guide/sysctl/vmswappiness は0〜200・既定60、0でもスワップが無効になるわけではない旨):https://docs.kernel.org/admin-guide/sysctl/vm.html
  • Linux カーネル ソース mm/oom_kill.cinvoked oom-killer: / oom-kill:constraint= / Out of memory: Killed process … の各メッセージ書式):https://raw.githubusercontent.com/torvalds/linux/v6.12/mm/oom_kill.c
  • Ubuntu マニュアル free(1)(resolute。available=スワップせずに新規アプリを起動できるメモリの推定値/usedtotal - available):https://manpages.ubuntu.com/manpages/resolute/en/man1/free.1.html
  • Ubuntu マニュアル swapon(8)(resolute。穴のあるファイル・CoWファイルシステムの制約、fallocate の注意と dd が最も確実である旨、--show / --all):https://manpages.ubuntu.com/manpages/resolute/en/man8/swapon.8.html
  • Ubuntu マニュアル systemd.swap(5)(resolute。nofail を付けると有効化に失敗してもブートが継続する旨):https://manpages.ubuntu.com/manpages/resolute/en/man5/systemd.swap.5.html
  • man journalctl(1)(-k--boot=0 を含意する):https://man7.org/linux/man-pages/man1/journalctl.1.html
  • man sysctl.d(5)(設定ファイルはファイル名の辞書順で、後ろのファイルが優先される):https://man7.org/linux/man-pages/man5/sysctl.d.5.html
  • Ubuntu Wiki Security/Features(dmesg_restrict は 20.10 以降 既定で有効):https://wiki.ubuntu.com/Security/Features
  • Launchpad Bug #2139289(systemd-oomd は Ubuntu Server では既定でインストールされていない旨の開発者コメント):https://bugs.launchpad.net/ubuntu/+source/ubuntu-meta/+bug/2139289
  • Ubuntu パッケージ検索 zram-config(24.04・26.04 とも universe に収録):https://packages.ubuntu.com/search?keywords=zram-config&searchon=names&suite=all&section=all
  • ConoHa VPS 料金(「1時間単位課金なので、使った分だけのお支払い」の記載):https://vps.conoha.jp/pricing/
  • ConoHa VPS スケールアップ・ダウン機能(「上位プランへ変更したり、戻したりでき」/「512MBプランではスケールアップ・ダウン機能をご利用いただけません」):https://vps.conoha.jp/function/scaleup/
  • ConoHa VPS サポート「プラン変更」(「スペックを変更できるのは停止しているVPSのみです」/VPS割引きっぷの連動):https://support.conoha.jp/v/changeplan/

※本文中のメモリ使用量・swapサイズの数値は、断りのない限り筆者環境(ConoHa VPS・Ubuntu・Nginx+PHP-FPM+MariaDB)での目安です。設定・バージョン・載せるアプリケーションによって大きく変わるため、実際の判断はご自身の環境で測ったうえで行ってください。ソフトウェアの挙動はバージョンによって変わります。料金・プラン変更の条件は変更されることがあるため、申し込み前に公式サイトで最新をご確認ください。

更新日:2026年8月25日

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コスト最小で制作をしたいという意識強め(笑)

目次