はじめに:メモリが枯渇したとき、OSは「誰」を停止するのか?
物理メモリの完全枯渇
オンプレミスサーバーや限られたメモリ(4GB〜16GB)のミニPCで、DockerコンテナやローカルLLM、データベースを動かしていると、いつか必ず 「物理メモリの完全枯渇」 に直面します。
その極限状態に達した瞬間、Linuxカーネルの最終防衛機構 oom_score_adj によるプロセスの停止優先度コントロールを実行し、最悪の悲劇が起こります。
- 「なぜかメモリを食っている元凶ではなく、命綱である SSHデーモン(sshd)やデータベース(MySQL)が倒された!」
- 「リモートからSSHログインすらできなくなり、サーバールームに走って物理電源長押しする羽目になった」
なぜカーネルは一番倒してはいけない重要プロセスを停止してしまうのか?
どうすれば、元凶のバッチ処理や開発コンテナだけを狙い撃ちで倒させ、管理基盤を守り抜けるのか?
本記事では、oom_score_adj によるプロセスの停止優先度コントロールと、vm.swappiness の最適調律 を解説します。
1. OOM Killerの採点ロジック:oom_score の真実
カーネルは、各プロセスの「悪質度(Badness)」を 0 〜 1000 のスコアで計算します。
基本的には「多くのメモリを消費しているプロセス」ほど高得点になりますが、プロセスの生存期間や権限によってもブレが生じます。
現在の各プロセスのスコアは、/proc から直接確認できます。
# (要点抜粋)
# (Source: https://github.com/ojisantech/)
# プロセス 1234 の現在の停止スコアを確認
cat /proc/1234/oom_score
# システム内で「今一番倒されそうなプロセス TOP 5」を表示
ps -eo pid,comm,pmem --sort=-pmem | head -n 6
2. 重要プロセスを「絶対不可侵」にする:oom_score_adj = -1000
Linuxカーネルは、ユーザーが各プロセスの停止優先度を -1000(絶対に倒すな) から +1000(真っ先に倒せ) の範囲で調整できるフックを用意しています。
① SSHデーモンを絶対不可侵にする
SSHが停止するとリモート復旧が不可能になるため、-1000 を設定して停止対象から完全除外します。
# (要点抜粋)
# (Source: https://github.com/ojisantech/)
# sshd プロセスのPIDを取得して絶対保護
sudo echo -1000 > /proc/$(pgrep -o sshd)/oom_score_adj
② systemd サービス単位で恒久設定する
サービス定義ファイル(Unitファイル)に OOMScoreAdjust を1行書くだけで、再起動後も永続的に保護されます。
逆に、メモリ暴走の危険がある自作バッチやテストスクリプトには OOMScoreAdjust=1000 を指定しておけば、メモリ逼迫時に真っ先に身代わりとして停止され、他の重要サービスを守ってくれます。
3. Docker コンテナ単位での優先度制御
Docker Composeでも、コンテナごとに oom_score_adj を設定できます。
4. カーネルスワップ調律:vm.swappiness の最適解
メモリが残り少なくなったときのカーネルの挙動を、/etc/sysctl.conf で最適化します。
# (要点抜粋)
# (Source: https://github.com/ojisantech/)
sudo sysctl --system
💻 コア実装・設定スニペット(抜粋)
# (要点抜粋)
# /etc/sysctl.d/99-memory-tuning.conf
# 既定値 60 -> 10 に引き下げ。
# 物理メモリをギリギリまで使い倒し、無駄なNVMe/SSDへのスワップアウト(速度低下)を防ぐ
vm.swappiness = 10
# メモリの過剰コミット(Overcommit)の挙動調整 (既定: 0 = ヒューリスティック)
vm.overcommit_memory = 0
# パニック時の自動再起動 (万が一カーネルパニックが起きたら 10秒後に自動リブート)
kernel.panic = 10
まとめ:OOM Killerと戦うな、飼いならせ
メモリ枯渇は、アクセス集中やデータ肥大化によってどんなシステムでも起こり得ます。
- SSHやデータベースには
OOMScoreAdjust=-1000を与えて不可侵にする - 重たい推論モデルやバッチには正のスコアを与えて「身代わり」にする
vm.swappiness=10で不必要なディスクI/Oスラッシングを防ぐ
このカーネルチューニングを施しておくことで、メモリ限界時でも「重要な管理画面やSSHはピンピン生きており、原因のプロセスだけが綺麗に切断されて即座に原因調査できる」という極めて強靭なインフラが完成します!
📚 さらに詳しいアーキテクチャ設計・パラメータ表・トラブルシューティング
最後までお読みいただきありがとうございます!
本記事が少しでも「役に立った」「あとで試したい」と感じていただけましたら、ぜひQiitaの 「いいね(♡)」 と 「ストック」、および アカウントのフォロー をいただけると今後の検証・執筆の大きな励みになります!
また、本記事のさらに踏み込んだ 「深層アーキテクチャ解説」「主要パラメータの技術的根拠」「現場アンチパターン・トラブルシューティング対応表」 は、以下のGitHub技術リファレンスにて公開しています。
👉 【第37弾 詳細技術リファレンス (QIITA_ARTICLE_DETAIL_37.md)】
⭐ 全14層・200パターンの自立型インフラ&オンプレAIリファレンス集(おじさんの武器庫)を順次公開中です。ぜひGitHubリポジトリへの Star (★) と X (@OjisanTechnical) のフォローもお願いいたします!
👉 GitHub リポジトリ: ojisantech/ojisan-arsenal
💡 【検証環境・個人研究(PoC)に関する注記】
本記事は、筆者個人の自宅検証環境(ホームラボ/仮想環境)において、公開情報およびOSS(オープンソースソフトウェア)を用いて独自に構築・検証した個人研究(PoC)の記録です。特定の企業・団体の実環境や業務上の非公開情報とは一切関係ありません。