【完全版】Linux OOM Killerの確認方法まとめ|ログの見方から原因調査・対策まで徹底解説

  • 作成日 2026.06.22
  • linux
【完全版】Linux OOM Killerの確認方法まとめ|ログの見方から原因調査・対策まで徹底解説

Linuxサーバーで「気づいたらプロセスが落ちていた」「アプリが突然再起動していた」という現象に遭遇することがあります。エラーログにも明確な記録がなく、原因が分からず途方に暮れる──そんな時に疑うべきが OOM Killer(Out Of Memory Killer)です。

しかし、OOM Killerの調査には独特の難しさがあり:

  • そもそもOOM Killerが発動したのかどうか分からない
  • どのログファイルを見ればいいのか分からない
  • ログは見つけたが何を意味しているのか読み解けない
  • どのプロセスが「殺された」のか特定できない
  • なぜそのプロセスが選ばれたのか分からない
  • 再発を防ぐにはどう設定すればいいのか分からない

など、つまづくポイントが多い領域です。

本記事では、OOM Killer確認方法と調査パターンを、リファレンスとしてまとめ直しました。OOM Killerの仕組みから、ログの探し方・読み方、発生有無の判定、犠牲プロセスの特定、メモリ使用量の調査、対策設定、トラブルシューティング、実用例、FAQまで完全網羅。この1本をブックマークすれば、OOM Killerに関するあらゆる疑問が解決します。


目次

結論:今すぐ確認できるコマンド10選

時間がない方向けに、超頻出の確認コマンドを先に示します。

# dmesgでOOM発生履歴を確認(最も基本)
dmesg | grep -i "killed process"

# dmesgでOOM関連の文脈をまとめて確認
dmesg | grep -i -E "oom|out of memory"

# systemd環境でjournalctlから確認
journalctl -k | grep -i "killed process"

# 直近のカーネルログのみに絞って確認
journalctl -k -b | grep -i oom

# /var/log/messages から確認(RHEL系)
sudo grep -i "killed process" /var/log/messages

# /var/log/syslog から確認(Debian/Ubuntu系)
sudo grep -i "killed process" /var/log/syslog

# 直近24時間以内のOOM発生を確認
journalctl -k --since "24 hours ago" | grep -i oom

# 現在のメモリ使用状況を確認(予防的チェック)
free -h

# プロセスごとのメモリ使用量トップ10
ps aux --sort=-%mem | head -10

# OOM発生時刻と前後のシステム状態をまとめて確認
journalctl -k --since "2026-06-19 03:00:00" --until "2026-06-19 03:10:00"

詳細は以下で順に解説します。


OOM Killer とは何か

OOM Killer(Out Of Memory Killer)は、Linuxカーネルに組み込まれた仕組みで、システムの空きメモリ(および swap)が枯渇した際に、強制的にいずれかのプロセスを終了させてメモリを解放する機能です。

メモリ + swap が枯渇
        │
        ▼
カーネルが OOM Killer を起動
        │
        ▼
各プロセスに "oom_score" を計算
        │
        ▼
最もスコアの高い(=最も「殺しても良い」と判断された)
プロセスを選んで SIGKILL 送信
        │
        ▼
該当プロセスが強制終了、メモリ解放

OOM Killerは最後の砦として動作するため、発動すること自体が「システムのメモリ設計に何らかの問題がある」サインです。発動後は必ず原因調査が必要です。

なぜプロセスが「選ばれる」のか

カーネルは各プロセスに oom_score という値を計算し、スコアが高いプロセスから優先的に終了させます。スコアは主に以下の要素で決まります。

要素スコアへの影響
使用メモリ量多いほどスコアが高い(狙われやすい)
実行時間短いほどスコアが高い傾向
oom_score_adjの設定値手動で調整可能(後述)
rootプロセスかどうかrootは若干優遇される傾向
子プロセスの数多いと若干スコアに影響

つまり「メモリを大量に使っている、比較的新しいプロセス」が狙われやすい傾向にあります。


OOM発生の確認方法(基本)

dmesg で確認する

dmesgはカーネルのリングバッファを表示するコマンドで、OOM Killerの動作履歴を確認する最も基本的な方法です。

# OOM関連の行だけ抽出
dmesg | grep -i -E "oom|out of memory|killed process"

# 出力例
[123456.789012] Out of memory: Killed process 12345 (java) total-vm:4194304kB, anon-rss:2097152kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4096kB oom_score_adj:0

⚠️ dmesgはカーネルのリングバッファが上限を超えると古いログから消えていきます。サーバー再起動後やログが大量に出た後は、過去のOOM履歴が失われている可能性があるため、journalctlや永続ログファイルも合わせて確認するのが確実です。

journalctl で確認する(systemd環境)

# カーネルログのみに絞って確認
journalctl -k | grep -i oom

# 今回起動後のログのみ
journalctl -k -b | grep -i "killed process"

# 期間を指定して確認
journalctl -k --since "2026-06-01" --until "2026-06-19" | grep -i oom

# 直近1時間以内
journalctl -k --since "1 hour ago" | grep -i oom

journalctldmesgと違い、再起動をまたいでログが永続化されている(journald の設定によりますが)ため、過去の発生履歴を遡りやすいのが利点です。

ログファイルから直接確認する

# Debian/Ubuntu系
sudo grep -i "killed process" /var/log/syslog
sudo grep -i "killed process" /var/log/syslog.1
sudo zgrep -i "killed process" /var/log/syslog.*.gz

# RHEL/CentOS系
sudo grep -i "killed process" /var/log/messages
sudo grep -i "killed process" /var/log/messages-*

# 過去のログも含めてまとめて検索(ローテート済みも対象)
sudo zgrep -i "killed process" /var/log/syslog* 2>/dev/null

ログローテーションで.gz圧縮されている過去ログにはzgrepを使うと展開せずに検索できます。

OOM発生の有無だけをサッと判定したい

# 発生していれば何か出力される、何もなければ発生なし
dmesg 2>/dev/null | grep -i "killed process" && echo "OOM発生あり" || echo "OOM発生なし(直近のdmesgには記録なし)"

# journalctlベースでの判定(より確実)
journalctl -k 2>/dev/null | grep -qi "killed process" && echo "OOM発生あり" || echo "OOM発生なし"

ログの読み方(OOMログのフィールド解説)

実際のOOM Killerログは情報量が多く、一見すると読みにくい構造をしています。

典型的なログの全体像

[123456.789012] java invoked oom-killer: gfp_mask=0x140cca(GFP_HIGHUSER_MOVABLE|__GFP_COMP), order=0, oom_score_adj=0
[123456.789020] CPU: 2 PID: 12345 Comm: java Not tainted 6.8.0-generic
[123456.789100] Mem-Info:
[123456.789200] ...(メモリ使用状況の詳細)...
[123456.790000] Tasks state (memory values in pages):
[123456.790100] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[123456.790200] [  1234]     0  1234     1024      256      53248        0             0 systemd
[123456.790300] [ 12345]  1000 12345  1048576   524288    4194304        0             0 java
[123456.790900] Out of memory: Killed process 12345 (java) total-vm:4194304kB, anon-rss:2097152kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4096kB oom_score_adj:0

各行の意味

ログ部分意味
java invoked oom-killerどのプロセスがメモリ確保を試みてOOM Killerの引き金になったか
gfp_mask=...メモリ確保時のカーネル内部フラグ(通常は無視してOK)
Mem-Info: 以降発生時点でのメモリ・swap全体の使用状況
Tasks state のテーブル発生時点で動いていた全プロセスのメモリ使用量一覧
Out of memory: Killed process実際に強制終了されたプロセス(引き金になったプロセスと別の場合も多い)

⚠️ 「OOM Killerを誘発したプロセス」と「実際に殺されたプロセス」は別物です。たとえばApacheがメモリ確保に失敗してOOM Killerを誘発しても、実際に殺されるのはメモリを最も食っている別のプロセス(MySQLなど)というケースが頻繁にあります。ログのinvoked oom-killerKilled processの両方を必ず確認してください。

“Killed process” 行の詳細フィールド

Killed process 12345 (java) total-vm:4194304kB, anon-rss:2097152kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4096kB oom_score_adj:0
フィールド意味
12345殺されたプロセスのPID
(java)プロセス名(コマンド名)
total-vm仮想メモリの総使用量
anon-rss物理メモリ上の匿名ページ使用量(≒実際に消費していたメモリの主要部分)
file-rssファイルマップされたメモリ使用量
UID実行ユーザーのUID
oom_score_adjそのプロセスに設定されていたスコア調整値

anon-rssを1024で割るとMB単位のおおよそのメモリ使用量が分かります(例: 2097152kB ≒ 2GB)。


発生時刻・頻度の調査

いつ発生したか時刻を特定する

# dmesgはシステム起動からの経過秒数(カーネルタイムスタンプ)で表示される
dmesg | grep -i "killed process"
# [123456.789012] Out of memory: Killed process ...

# 起動時刻を確認して実時刻に変換
uptime -s
# 2026-06-15 08:00:00

# dmesgに実時刻を表示させる(-Tオプション)
dmesg -T | grep -i "killed process"
# [Fri Jun 19 03:12:45 2026] Out of memory: Killed process ...

# journalctlは最初から実時刻表示
journalctl -k | grep -i "killed process"

dmesg -Tを使うのが最も手軽に実時刻へ変換する方法です。

発生頻度・回数を集計する

# 何回発生しているか件数をカウント
dmesg | grep -ci "killed process"

# journalctlベースで日別に集計
journalctl -k --since "30 days ago" | grep -i "killed process" | \
    awk '{print $1, $2, $3}' | sort | uniq -c

# 殺されたプロセス名ごとに集計(傾向分析)
dmesg -T | grep -i "killed process" | \
    grep -oP '(?<=Killed process \d{1,10} \().*?(?=\))' | sort | uniq -c | sort -rn

特定のプロセスが繰り返し狙われている場合は、そのプロセスのメモリリークやメモリ設定(JVMヒープサイズなど)の見直しが必要なサインです。


発生時のシステム状態を調査する

発生時刻前後のログをまとめて確認

# journalctlで時間範囲を指定して前後の文脈を見る
journalctl -k --since "2026-06-19 03:10:00" --until "2026-06-19 03:15:00"

# 発生時刻の前後5分を一括確認するワンライナー
OOM_TIME=$(dmesg -T | grep -i "killed process" | tail -1 | grep -oP '(?<=\[)[^]]+(?=\])')
echo "OOM発生時刻: $OOM_TIME"

メモリ・swap使用量の推移を調べる(事後分析)

OOM発生後にリアルタイムでメモリ状況を見ることはできないため、監視ツールのログ(あれば)や、sarコマンドの記録を確認します。

# sysstatパッケージのsarでメモリ推移を確認(事前に記録されている場合のみ)
sar -r -f /var/log/sa/sa19

# 特定時刻周辺のメモリ使用率を確認
sar -r -s 03:00:00 -e 03:30:00

sarを使うには事前にsysstatパッケージが稼働している必要があります。OOM対策の一環として、平時からsarやNode Exporter等のメトリクス収集を有効にしておくことを強く推奨します。

現在のメモリ状況を確認する(予防的)

# メモリ全体の使用状況
free -h

# 出力例
#               total        used        free      shared  buff/cache   available
# Mem:           7.8Gi       6.2Gi       312Mi       128Mi       1.3Gi       1.1Gi
# Swap:          2.0Gi       1.8Gi       200Mi

# 1秒間隔で継続監視
watch -n 1 free -h

# プロセスごとのメモリ使用量トップ10
ps aux --sort=-%mem | head -10

# topでメモリ順にソート表示
top -o %MEM

available列が極端に少ない、またはswapusedが増え続けている状態は、OOM発生の前兆として注意が必要です。


犠牲プロセス(殺されたプロセス)の特定

PIDとプロセス名を取り出す

# Killed processの行から PID とプロセス名を抽出
dmesg -T | grep -i "killed process" | \
    grep -oP 'Killed process \K\d{1,10} \(\K[^)]+'

# より見やすく整形
dmesg -T | grep -i "killed process" | \
    awk -F'[][]' '{print $2}' | while read -r line; do echo "$line"; done

該当プロセスが何のサービスだったか調査

# PIDからsystemdサービス名を逆引き(プロセスが既に終了しているため直接は不可、ログから推測)
# OOMログの "Comm:" 行や "Killed process" のプロセス名から該当サービスを特定
systemctl status <推測したサービス名>

# 該当プロセス名で稼働中の類似サービスを横断検索
systemctl list-units --type=service | grep -i java

# journalctlでそのサービスの該当時刻のログを確認
journalctl -u myapp.service --since "2026-06-19 03:10:00" --until "2026-06-19 03:15:00"

OOM Killerに殺されたプロセスは強制終了(SIGKILL)のため、アプリ自身のログには正常な終了処理の記録が残りません。「ログが途中でぷつっと切れている」こと自体がOOM Killerによる強制終了の状況証拠になります。

コンテナ環境(Docker/Kubernetes)での確認

# コンテナがOOMKilledで終了したか確認
docker inspect <container_id> | grep -i oomkilled
# "OOMKilled": true,

# Docker全体のイベントから確認
docker events --filter event=oom

# Kubernetesでpodの状態を確認
kubectl describe pod <pod_name> | grep -A 5 "Last State"
# Last State:     Terminated
#   Reason:       OOMKilled
#   Exit Code:    137

# Kubernetesイベント全体から確認
kubectl get events --field-selector reason=OOMKilling

コンテナ環境ではコンテナ自身のメモリ制限(cgroup)によるOOM Killと、ホストマシン全体のメモリ枯渇によるOOM Killの2種類があるため、どちらが発生したか切り分けが必要です(後述)。


ホストOOM と コンテナ(cgroup)OOM の違い

2種類のOOM Killerの違い

種類発動条件確認方法
ホストOOMシステム全体の空きメモリ・swapが枯渇dmesg/journalctl -k
cgroup OOMコンテナに割り当てられたメモリ上限(--memory等)に到達docker inspectdmesg(cgroup関連の記述あり)

cgroup OOM もdmesgに記録される

# cgroup起因のOOMもdmesgに残る(メッセージに"memory cgroup out of memory"等が含まれる)
dmesg -T | grep -i -E "memory cgroup|cgroup.*oom"

# 出力例
[Fri Jun 19 03:12:45 2026] memory cgroup out of memory: Killed process 23456 (node) total-vm:..., cgroup-path: /docker/abc123...

cgroup-pathにコンテナIDらしき文字列が含まれていれば、ホスト全体ではなく特定コンテナのメモリ制限に起因するOOMだと判断できます。

Kubernetesでのリソース制限確認

# Podのメモリ制限(limit)を確認
kubectl get pod <pod_name> -o jsonpath='{.spec.containers[*].resources}'

# limitに対する実際の使用量を確認
kubectl top pod <pod_name>

limitを超えるとコンテナだけがOOM Killされ、ホスト全体には影響しません。一方limitを設定していない(無制限)コンテナは、ホスト全体のメモリを圧迫しホストOOMの引き金になり得ます。


OOM Killerの対策・チューニング

oom_score_adj で優先度を調整する

特定のプロセスを「優先的に殺されたくない」または「率先して犠牲にしたい」場合に設定します。

# 現在のoom_score_adjを確認
cat /proc/<PID>/oom_score_adj

# 現在の実効スコア(oom_score)を確認(参考値)
cat /proc/<PID>/oom_score

# 値を変更(-1000〜1000、低いほど殺されにくい)
echo -500 > /proc/<PID>/oom_score_adj

# 絶対に殺されたくない場合(-1000で対象外になる)
echo -1000 > /proc/<PID>/oom_score_adj

# 優先的に犠牲にしたい場合
echo 500 > /proc/<PID>/oom_score_adj
意味
-1000OOM Killerの対象から完全に除外
-500 程度殺されにくくする
0(デフォルト)通常通りスコア計算
5001000優先的に犠牲にする

⚠️ -1000を多用すると「殺せるプロセスがなくなりシステム全体がフリーズする」リスクがあるため、本当に重要なプロセス(DBなど)にのみ慎重に設定します。

systemdサービスに恒久設定する

# /etc/systemd/system/myapp.service.d/override.conf
[Service]
OOMScoreAdjust=-500
sudo systemctl daemon-reload
sudo systemctl restart myapp

swap容量を見直す

# 現在のswap状況確認
swapon --show
free -h

# swapファイルを追加作成する例(2GB)
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 永続化(/etc/fstabに追記)
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

swapを増やすとOOM発生自体は減りますが、swap多用によるパフォーマンス低下とのトレードオフがあるため、根本対策はメモリ使用量の削減・増設が基本です。

vm.overcommit_memory の調整

# 現在の設定確認
cat /proc/sys/vm/overcommit_memory

# 一時的に変更
sudo sysctl vm.overcommit_memory=2

# 永続化
echo "vm.overcommit_memory = 2" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
動作
0(デフォルト)ヒューリスティックな判定でオーバーコミットを許可
1常にオーバーコミットを許可(メモリ確保失敗が起きにくい代わりにOOM Killer頼みになる)
2オーバーコミットを厳密に制限(設定によりメモリ確保自体が早期に失敗するようになる)

2に設定すると「OOM Killerが発動する前に、アプリ側でmalloc失敗としてエラーハンドリングできる」可能性が高まりますが、システム全体のメモリ効率は下がる場合があります。

Docker/Kubernetesでメモリ上限を明示する

# Dockerでメモリ上限を設定
docker run -m 512m --memory-swap 512m myapp

# docker-composeでの指定例
# deploy:
#   resources:
#     limits:
#       memory: 512M
# Kubernetes Podでのrequests/limits設定
resources:
  requests:
    memory: "256Mi"
  limits:
    memory: "512Mi"

コンテナ単位で上限を明示することで、1つのコンテナの暴走がホスト全体のOOMを引き起こす事態を防止できます。

アプリケーション側の対策(JVM例)

# JVMのヒープサイズを物理メモリに対して適切に制限
java -Xmx512m -Xms256m -jar myapp.jar

# コンテナ環境ではコンテナのメモリ制限を自動認識させる(JDK 10+)
java -XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -jar myapp.jar

JVMやNode.jsなど、独自のメモリ管理を行うランタイムは、OS全体のメモリ量とコンテナの制限値を正しく認識させる設定が重要です。


監視・予防的アラートの設定

簡易監視スクリプト

#!/bin/bash
# oom-watch.sh: OOM発生を検知してアラート
LAST_CHECK_FILE="/tmp/oom_last_check"
touch -d "5 minutes ago" "$LAST_CHECK_FILE" 2>/dev/null || true

NEW_OOM=$(journalctl -k --since "5 minutes ago" | grep -i "killed process")

if [ -n "$NEW_OOM" ]; then
    echo "OOM Killer発動を検知:" 
    echo "$NEW_OOM"
    # Slack通知等をここに追加
    # curl -X POST -H 'Content-type: application/json' \
    #     --data "{\"text\":\"OOM Killer発動: $NEW_OOM\"}" "$SLACK_WEBHOOK_URL"
fi
# cronで5分ごとに監視
*/5 * * * * /usr/local/bin/oom-watch.sh

メモリ使用率の事前アラート(OOM発生前に検知)

#!/bin/bash
# memory-alert.sh: メモリ使用率が閾値を超えたら警告
THRESHOLD=90
USAGE=$(free | awk '/Mem:/ {printf("%.0f", $3/$2 * 100)}')

if [ "$USAGE" -ge "$THRESHOLD" ]; then
    echo "メモリ使用率が${USAGE}%に到達(閾値${THRESHOLD}%)"
fi

OOM Killerは「発動してから気づく」のではなく、発動する前にメモリ使用率を監視して予防するのが本来あるべき運用です。Prometheus + Node Exporter + Alertmanager等の本格的な監視基盤の導入を推奨します。


トラブルシューティング

dmesgで何も見つからない(でもプロセスが落ちている)

# dmesgのバッファが上書きされている可能性。journalctlを確認
journalctl -k --since "7 days ago" | grep -i oom

# それでもない場合、永続ログが無効化されていないか確認
journalctl --disk-usage
cat /etc/systemd/journald.conf | grep -i storage

# Storage=volatile になっていると再起動でログが消える
sudo sed -i 's/#Storage=auto/Storage=persistent/' /etc/systemd/journald.conf
sudo systemctl restart systemd-journald

journald.confStorage=volatile(メモリ上のみ保持)になっていると、再起動と同時にログが消失するためpersistentへの変更を検討してください。

“Killed process” は見つかるが原因のプロセスが分からない

# Tasks stateテーブルから発生時点の全プロセス一覧を確認
dmesg -T | grep -A 200 "invoked oom-killer" | grep -B 200 "Killed process" | head -100

# rss(実メモリ使用量)の降順で見たい場合は該当ブロックを抽出してソート
dmesg -T | awk '/invoked oom-killer/,/Killed process/' | \
    awk '{print $NF, $0}' | sort -rn | head -20

「殺されたプロセス」自体がメモリを大量消費していたとは限りません。Tasks stateテーブル全体を見て、実際に最もメモリを使っていたプロセスを特定することが重要です。

OOM Killerが頻発する

# 頻度を確認
dmesg -T | grep -ci "killed process"

# 同じプロセス名が繰り返し狙われていないか確認
dmesg -T | grep -i "killed process" | grep -oP '(?<=\().*?(?=\))' | sort | uniq -c | sort -rn

同一プロセスが繰り返し犠牲になっている場合は、メモリリークまたはそもそものメモリ割り当て不足を疑い、アプリログ・APM(Application Performance Monitoring)ツールでの詳細調査に進みます。

重要なプロセス(DBなど)が毎回狙われる

# 現在のoom_score_adjを確認
cat /proc/$(pgrep -x mysqld)/oom_score_adj

# 優先度を下げて殺されにくくする
echo -500 | sudo tee /proc/$(pgrep -x mysqld)/oom_score_adj

恒久対策としてはsystemdのOOMScoreAdjust設定、またはそもそものメモリ設計見直し(メモリ増設、不要プロセスの削減)を検討してください。

コンテナが理由もなく再起動する

# OOMKilledかどうかまず確認
docker inspect <container_id> --format='{{.State.OOMKilled}}'

# trueの場合、メモリ制限値を見直す
docker inspect <container_id> --format='{{.HostConfig.Memory}}'

# Kubernetesの場合
kubectl describe pod <pod_name> | grep -i oomkilled -A 3

OOMKilled: trueであれば、コンテナのメモリlimit設定が実際のアプリ要求量に対して低すぎる可能性が高いです。

root権限がなくてログが見られない

# 多くのディストリビューションでdmesgは一般ユーザーでも閲覧可能な場合がある
dmesg | grep -i oom

# 権限エラーが出る場合はsudoが必要
sudo dmesg | grep -i oom

# journalctlも同様
journalctl -k | grep -i oom
# Permission denied の場合
sudo journalctl -k | grep -i oom

kernel.dmesg_restrict=1が設定されている環境では一般ユーザーからdmesgが見えないため、sudoが必須になります。


実用パターン集

実務でよく使う調査・対策コマンドを網羅します。

日常監視系

# 直近のOOM発生有無を毎朝チェック(cron例)
0 9 * * * journalctl -k --since "24 hours ago" | grep -qi oom && \
    echo "OOM発生あり、要確認" | mail -s "OOM Alert" admin@example.com

# メモリ使用率を定期記録
*/10 * * * * free -h >> /var/log/memory-history.log

# swap使用量が増加傾向にないか確認
*/30 * * * * free | awk '/Swap/ {print $3}' >> /var/log/swap-trend.log

調査・診断系

# OOM発生時刻一覧をCSVっぽく出力
dmesg -T | grep -i "killed process" | \
    sed -E 's/^\[([^]]+)\].*Killed process ([0-9]+) \(([^)]+)\).*/\1,\2,\3/'

# 過去30日分のOOM発生統計
journalctl -k --since "30 days ago" | grep -i "killed process" | wc -l

# サービス別にOOMで落ちた回数を集計
for svc in mysql nginx java node; do
    count=$(dmesg -T | grep -ci "killed process.*($svc)")
    echo "$svc: $count 回"
done

対策・予防系

# 重要サービスのoom_score_adjを一括設定
for pid in $(pgrep mysqld); do
    echo -500 | sudo tee /proc/$pid/oom_score_adj
done

# メモリ上限を明示してDockerコンテナを起動
docker run -d --name myapp -m 1g --memory-swap 1g myapp:latest

# swap追加後、swappinessを調整(swap使用を抑制気味に)
sudo sysctl vm.swappiness=10
echo "vm.swappiness = 10" | sudo tee -a /etc/sysctl.conf

レポート作成系

# OOM調査レポートを1ファイルにまとめて出力
{
    echo "=== OOM調査レポート $(date) ==="
    echo ""
    echo "--- OOM発生履歴 ---"
    journalctl -k --since "7 days ago" | grep -i "killed process"
    echo ""
    echo "--- 現在のメモリ状況 ---"
    free -h
    echo ""
    echo "--- メモリ使用量トップ10 ---"
    ps aux --sort=-%mem | head -10
    echo ""
    echo "--- swap状況 ---"
    swapon --show
} > /tmp/oom-report-$(date +%Y%m%d).txt

cat /tmp/oom-report-$(date +%Y%m%d).txt

OOM Killer 関連ツール

視覚的にメモリ状況を確認するツール

# htop(topの高機能版、インストールが必要な場合あり)
sudo apt install htop   # Debian/Ubuntu
sudo yum install htop   # RHEL/CentOS
htop

# smemでプロセスごとの実メモリ消費を正確に確認
sudo apt install smem
smem -rs uss -k | head -10

pstop%MEMは共有メモリの扱いで実態より過大/過小に見えることがあるため、より正確な値が必要な場合はsmem(USS: Unique Set Size)の利用を推奨します。

earlyoom(早期OOM対策ツール)

# インストール
sudo apt install earlyoom

# カーネルのOOM Killerより早いタイミングでプロセスを終了させ、
# システムフリーズを防ぐデーモン
sudo systemctl enable --now earlyoom

# 設定ファイル
cat /etc/default/earlyoom

earlyoomはカーネルのOOM Killerが発動する前段階でメモリ逼迫を検知し、ユーザー空間で先回りしてプロセスを終了させることで、カーネルOOM Killer特有の「発動までシステムが固まる」問題を緩和します。


よくある質問(FAQ)

Q1. OOM Killerが発動したかどうか、一番確実な確認方法は?

journalctl -k --since "30 days ago" | grep -i "killed process"

dmesg単体は再起動でバッファが消えるため、永続化されたjournalctlでの確認が最も確実です。journald未導入の古い環境では/var/log/syslogまたは/var/log/messagesを確認してください。

Q2. “invoked oom-killer” と “Killed process” の違いは?

invoked oom-killerメモリ確保に失敗してOOM Killerの発動トリガーになったプロセスKilled process実際に強制終了されたプロセスです。両者は別プロセスであることが多く、必ず両方確認する必要があります。

Q3. OOM Killerのログにタイムスタンプが秒数(経過時間)で出て分かりにくいです

dmesg -T | grep -i "killed process"

-Tオプションで実時刻表示に変換できます。journalctl -kは最初から実時刻で表示されます。

Q4. プロセスがOOM Killerで落ちたのか、別の理由(クラッシュ等)で落ちたのか見分けたい

# OOM Killerによる強制終了ならdmesg/journalctlにログが残る
dmesg -T | grep -i "killed process.*プロセス名"

# 何も見つからなければOOM以外の原因(アプリ自体のクラッシュ等)を疑う
journalctl -u myapp.service --since "発生時刻"

OOM Killerによる終了はSIGKILL(強制終了)のため、アプリ側のログには通常のエラーログが残りません。「ログが唐突に途切れている」のもOOMの状況証拠です。

Q5. 特定のプロセスを絶対にOOM Killerの対象にしたくない

echo -1000 > /proc/<PID>/oom_score_adj

-1000で完全に対象外にできますが、多用するとシステム全体がメモリ枯渇でフリーズするリスクがあるため、本当に必要なプロセス(重要なDB等)に限定してください。

Q6. swapを増やせばOOM Killerは発生しなくなりますか?

発生頻度は減らせますが、根本解決ではありません。swap使用が増えるとディスクI/Oに律速されパフォーマンスが大幅に低下するため、メモリ不足の根本原因(アプリのメモリリーク、メモリ要求量の見積もり不足)への対処が本質的な対策です。

Q7. Dockerコンテナだけが落ちて、ホストは無事でした。これもOOM Killerですか?

はい、cgroup OOMと呼ばれる現象です。コンテナに設定した-m(メモリ上限)にコンテナ内の使用量が到達すると、ホスト全体に影響を与えずそのコンテナのプロセスだけがOOM Killされます。

docker inspect <container_id> --format='{{.State.OOMKilled}}'

Q8. OOM Killerの発動を完全に無効化できますか?

カーネルレベルで完全に無効化することは推奨されません(メモリ枯渇時にシステム全体がハングするリスクが高まるため)。vm.overcommit_memory=2等で発動条件を厳しくする、または特定プロセスをoom_score_adj=-1000で除外する形が現実的です。

Q9. クラウド環境(AWS EC2等)でもOOM Killerの確認方法は同じですか?

はい、同じLinuxカーネルの仕組みのためdmesg/journalctlで同様に確認できます。ただし、マネージドサービス(ECS、Kubernetesのマネージドノードなど)の場合は、クラウド側の監視コンソール(CloudWatch Logs等)経由での確認が必要な場合もあります。

Q10. OOM発生の通知を自動化したいです

# crontabで定期チェック + Slack通知の例
*/5 * * * * journalctl -k --since "5 minutes ago" | grep -qi "killed process" && \
    curl -X POST -H 'Content-type: application/json' \
    --data '{"text":"OOM Killer発動を検知しました"}' "$SLACK_WEBHOOK_URL"

より本格的な運用では、Prometheus Node Exporterのnode_vmstat_oom_killメトリクスやAlertmanagerと組み合わせた監視基盤の構築を推奨します。


参考リンク・関連資料

公式ドキュメント

関連記事(本サイト)


まとめ

OOM KillerはLinuxカーネルがメモリ枯渇時にシステム全体のフリーズを防ぐための最終手段。要点を再整理します。

  • 基本の確認コマンド: dmesg | grep -i "killed process"journalctl -k | grep -i oom
  • dmesgはバッファが消える: 永続ログのjournalctl/var/log/syslogも必ず確認
  • 2つのプロセスに注目: invoked oom-killer(誘発)とKilled process(実際の犠牲者)は別物
  • 時刻変換は dmesg -T: 経過秒数表記を実時刻に変換できる
  • コンテナ環境は2種類のOOM: ホストOOMとcgroup OOM(docker inspectOOMKilledで判別)
  • 対策の基本: oom_score_adjでの優先度調整、systemdのOOMScoreAdjust、コンテナの-m明示設定
  • 根本対策はメモリ設計: swap増設は延命策、メモリリーク調査やリソース見積もり直しが本質
  • 予防が最重要: 発動後の調査だけでなく、メモリ使用率の事前監視・アラート設定を整備する

これらの知識は、Linuxサーバー運用・障害対応・キャパシティプランニングなど、システム管理のあらゆる場面で必須です。本記事をブックマークしておけば、いつでも適切にOOM Killerの発生有無を確認し、原因調査と対策につなげられるようになります。


本記事は2026年6月時点の情報をもとに、systemd採用ディストリビューション(Debian/Ubuntu、RHEL系)での動作確認に基づき作成しています。カーネルバージョンやディストリビューションによってログの細部表記が異なる場合があるため、最新の情報は公式カーネルドキュメントもあわせてご確認ください。