5分でわかるサーバメモリ不足対策【OOM killer発動前にやるべきこと】
はじめに - 深夜の障害対応、経験ありませんか?
こんにちは、ハンズオンラボ運営メンバーのわたるです。インフラエンジニア歴10年、監視オペレーターから始まり、現在は設計・構築まで幅広く担当しています。
「深夜にアプリケーションサーバが突然ダウン...原因はOOM killer」
この文章を見て、ドキッとした方もいるのではないでしょうか?私自身、freeコマンドでメモリ使用率99%を確認して青ざめた経験があります。
この記事では、以下の内容をお届けします:
- サーバメモリ不足の原因と対策を5つのステップで解説
-
free、top、vmstatコマンドの実践的な使い方 - OOM killerの仕組みと発動前に対処する方法
- 実務で使える監視アラート設定のポイント
読了時間は約5分。サーバが突然重くなったり、「Out of Memory」のログを見て焦った経験がある方は、ぜひ最後までお付き合いください。
ステップ1: 現在のメモリ状況を把握する【freeコマンド】
具体的なエピソード
ある日の深夜、アプリケーションサーバが応答しなくなりました。ログを確認すると「Out of memory: Kill process...」の文字が。OOM killerが発動していたのです。
まず私がやったのは、freeコマンドでメモリ使用状況を確認することでした。
なぜ重要なのか
メモリ不足の対策は、現状把握から始まります。物理メモリがどれだけ使われているか、スワップ領域は発生しているか、これらを知らなければ適切な対処ができません。
実践的な使い方
# 基本的な使い方(MB単位で表示)
$ free -m
total used free shared buff/cache available
Mem: 7823 7654 89 45 79 89
Swap: 2047 1890 157
freeコマンド主要オプション一覧
| オプション | 効果 | 使用例 |
|---|---|---|
-m |
メガバイト単位で表示 | free -m |
-g |
ギガバイト単位で表示 | free -g |
-h |
人間が読みやすい形式で表示(KB/MB/GB自動) | free -h |
-t |
合計行を表示 | free -m -t |
-s [秒] |
指定秒数ごとに更新表示 | free -m -s 5 |
-w |
バッファとキャッシュを分けて表示 | free -m -w |
出力項目の見方
| 項目 | 意味 |
|---|---|
total |
物理メモリの総容量 |
used |
使用中のメモリ量 |
free |
完全に未使用のメモリ量 |
shared |
共有メモリとして使用されている量 |
buff/cache |
バッファ/キャッシュとして使用されている量 |
available |
新規プロセスが利用可能なメモリ量(重要!) |
注目すべきはavailableの値です。これが物理メモリの10%以下になると危険信号。私の場合は89MBしかなく、完全にレッドゾーンでした。
ステップ2: メモリを大量に使っているプロセスを特定する【topコマンド】
具体的なエピソード
メモリ不足の原因を突き止めるため、次はtopコマンドでプロセスごとのメモリ使用量を確認しました。すると、あるJavaアプリケーションのプロセスが物理メモリの70%近くを消費していることが判明しました。
なぜ重要なのか
メモリリークを起こしているプロセスを特定できれば、そのプロセスを再起動することで一時的に問題を回避できます。根本的な解決には至らなくても、サービス継続のための時間を稼ぐことができます。
実践的な使い方
# topコマンドを起動
$ top
# 起動後、以下のキー操作でメモリ順にソート
Shift + M # メモリ使用率順に並び替え
Shift + P # CPU使用率順に並び替え(デフォルト)
top - 03:45:21 up 15 days, 5:32, 2 users, load average: 2.15, 1.89, 1.67
Tasks: 178 total, 2 running, 176 sleeping, 0 stopped, 0 zombie
%Cpu(s): 15.3 us, 3.2 sy, 0.0 ni, 80.5 id, 0.8 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 7823.4 total, 89.2 free, 7654.8 used, 79.4 buff/cache
MiB Swap: 2047.0 total, 157.2 free, 1889.8 used. 89.8 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
3421 app 20 0 8520124 5.3g 18436 S 5.3 69.2 256:42.18 java
1892 mysql 20 0 2789456 1.2g 23876 S 2.1 15.8 189:34.56 mysqld
topコマンド主要オプション一覧
| オプション | 効果 | 使用例 |
|---|---|---|
-d [秒] |
更新間隔を指定 | top -d 5 |
-n [回数] |
指定回数更新後に終了 | top -n 3 |
-b |
バッチモード(非対話的)で実行 | top -b -n 1 > top.log |
-p [PID] |
特定のプロセスIDのみ監視 | top -p 3421 |
-u [ユーザー] |
特定ユーザーのプロセスのみ表示 | top -u app |
-o [フィールド] |
指定フィールドでソート | top -o %MEM |
top起動後の対話キー操作
| キー操作 | 効果 |
|---|---|
Shift + M |
メモリ使用率順にソート |
Shift + P |
CPU使用率順にソート |
k |
プロセスを終了(killシグナル送信) |
1 |
CPU毎の使用率を表示 |
c |
コマンドのフルパスを表示/非表示 |
f |
表示フィールドのカスタマイズ |
h |
ヘルプ表示 |
q |
top終了 |
出力項目の見方(プロセス情報)
| 項目 | 意味 |
|---|---|
PID |
プロセスID |
USER |
プロセスの実行ユーザー |
VIRT |
仮想メモリサイズ(プロセスが確保した総メモリ) |
RES |
物理メモリ使用量(重要!) |
SHR |
共有メモリサイズ |
%MEM |
物理メモリ使用率 |
TIME+ |
CPU使用時間の累計 |
COMMAND |
プロセス名/コマンド |
RES(Resident Memory)の値に注目してください。これが物理メモリをどれだけ実際に消費しているかを示します。
私の場合、PID 3421のJavaプロセスが5.3GBも消費していることが判明。このプロセスを再起動することで、メモリ使用率を一時的に70%台まで下げることができました。
ステップ3: メモリの詳細な動作状況を確認する【vmstatコマンド】
具体的なエピソード
一時的な回避はできましたが、根本原因を探るため、メモリの動的な挙動を観察する必要がありました。そこで使ったのがvmstatコマンドです。
なぜ重要なのか
vmstatは、メモリだけでなくCPU、ディスクI/O、スワップの発生状況を時系列で監視できます。特に、スワップイン/スワップアウトの発生頻度を確認することで、メモリ不足がどれほど深刻かを判断できます。
実践的な使い方
# 5秒間隔で3回表示
$ vmstat 5 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
2 0 1889876 91232 15432 64128 256 512 45 123 892 1543 15 3 80 2 0
1 0 1895234 87456 15432 64128 512 768 52 134 915 1621 18 4 76 2 0
3 0 1902145 82134 15432 64128 1024 1235 48 145 967 1789 21 5 71 3 0
vmstatコマンド主要オプション一覧
| オプション | 効果 | 使用例 |
|---|---|---|
[間隔] [回数] |
指定間隔(秒)で指定回数表示 | vmstat 5 10 |
-a |
アクティブ/非アクティブメモリを表示 | vmstat -a 5 |
-s |
メモリ統計情報を表示 | vmstat -s |
-m |
スラブ情報を表示(カーネルメモリ) | vmstat -m |
-d |
ディスク統計情報を表示 | vmstat -d |
-t |
タイムスタンプ付きで表示 | vmstat -t 5 |
-S [単位] |
単位を指定(k/K/m/M) | vmstat -S M 5 |
出力項目の見方
procs(プロセス状態)
| 項目 | 意味 |
|---|---|
r |
実行待ちプロセス数 |
b |
ブロックされたプロセス数(I/O待ち) |
memory(メモリ状況)
| 項目 | 意味 |
|---|---|
swpd |
使用中のスワップ領域(KB) |
free |
空きメモリ(KB) |
buff |
バッファに使用されているメモリ(KB) |
cache |
キャッシュに使用されているメモリ(KB) |
swap(スワップ状況/重要!)
| 項目 | 意味 |
|---|---|
si |
スワップイン量(KB/秒) - ディスクからメモリへ |
so |
スワップアウト量(KB/秒) - メモリからディスクへ |
io(ディスクI/O)
| 項目 | 意味 |
|---|---|
bi |
ブロックデバイスから受信(ブロック/秒) |
bo |
ブロックデバイスへ送信(ブロック/秒) |
system(システム)
| 項目 | 意味 |
|---|---|
in |
割り込み回数(/秒) |
cs |
コンテキストスイッチ回数(/秒) |
cpu(CPU使用率)
| 項目 | 意味 |
|---|---|
us |
ユーザー空間CPU使用率 |
sy |
カーネル空間CPU使用率 |
id |
アイドル率 |
wa |
I/O待ち率 |
st |
仮想マシンに奪われた時間率 |
注目すべきはsiとsoの値です。これらが頻繁に発生している(例:100以上)場合、物理メモリ不足によりスワップが発生し、パフォーマンスが著しく低下している証拠です。
私のケースでは、soの値が512〜1235と高く、メモリからディスクへのスワップアウトが継続的に発生していました。これは物理メモリの追加やプロセスの最適化が必要な状態です。
ステップ4: OOM killerの仕組みを理解して予防する
具体的なエピソード
「Out of memory: Kill process」というログを初めて見たとき、正直何が起こったのか理解できませんでした。調べてみると、これはLinuxカーネルが持つ自衛機能だとわかりました。
なぜ重要なのか
OOM(Out Of Memory) killerは、物理メモリとスワップ領域が枯渇した際に、カーネルが最もメモリを消費しているプロセスを強制終了する仕組みです。これを理解していないと、突然アプリケーションが落ちる原因がわからず、対策も打てません。
OOM killerの発動条件と仕組み
OOM killerが発動するのは以下の条件です:
- 物理メモリが枯渇
- スワップ領域も枯渇(または設定されていない)
- 新しいメモリ割り当てができない状態
発動すると、カーネルは各プロセスに「OOMスコア」を計算し、スコアが最も高い(=メモリを最も消費している)プロセスをSIGKILLシグナルで強制終了します。
# 各プロセスのOOMスコアを確認
$ cat /proc/[PID]/oom_score
# OOMスコア調整値を確認(-1000〜1000、低いほど終了されにくい)
$ cat /proc/[PID]/oom_score_adj
予防策
1. メモリ監視アラートの設定
CloudWatchやZabbix、Datadogなどの監視ツールで、メモリ使用率が80%を超えたらアラートを発報する設定を行います。
# CloudWatch Alarmの設定例(AWS CLI)
aws cloudwatch put-metric-alarm \
--alarm-name high-memory-usage \
--metric-name MemoryUtilization \
--namespace System/Linux \
--statistic Average \
--period 300 \
--threshold 80 \
--comparison-operator GreaterThanThreshold
2. スワップ領域の設定
スワップ領域を設定することで、物理メモリ枯渇時の猶予時間を作れます。
# スワップファイル作成(2GB)
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永続化(/etc/fstabに追記)
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
3. OOMスコアの調整
重要なプロセスが終了されないよう、OOMスコアを調整します。
# 重要なプロセスのOOMスコア調整値を下げる(終了されにくくする)
echo -500 | sudo tee /proc/[PID]/oom_score_adj
私の失敗と学び
私の最大の失敗は、CloudWatchアラームを設定していなかったことです。事前に監視アラートを設定しておけば、OOM killer発動前に気づいて対処できました。この経験から、監視設定の重要性を痛感し、以降は必ず80%でアラート、90%でクリティカルアラートを設定するようにしています。
ステップ5: 根本的な対策を実施する
具体的なエピソード
一時的な回避策でサービスは継続できましたが、これは根本解決ではありません。再発防止のため、以下の対策を実施しました。
実施した対策
1. アプリケーションコードの見直し
メモリリークが疑われるJavaアプリケーションのコードをレビューし、不要なオブジェクトを保持し続けている箇所を修正しました。
2. JVMヒープサイズの最適化
Javaの最大ヒープサイズ(-Xmx)を物理メモリの70%程度に制限し、無制限に拡大しないよう設定しました。
# Java起動オプション例
java -Xms2g -Xmx5g -jar application.jar
3. 物理メモリの増設検討
EC2インスタンスタイプをt3.medium(4GB)からt3.large(8GB)にスケールアップしました。
4. 定期的なメモリ使用状況のモニタリング
cronで定期的にfreeとtopの結果をログに記録し、メモリ使用のトレンドを把握できるようにしました。
# crontab設定例(5分ごとにメモリ状況を記録)
*/5 * * * * free -m >> /var/log/memory_check.log
Windows Serverの場合は?
Windows Serverでも同様の対策が可能です:
- タスクマネージャー: プロセスごとのメモリ使用量を確認
- パフォーマンスモニター: メモリカウンターで詳細監視
-
PowerShellコマンド:
Get-Process | Sort-Object -Property WS -Descendingでメモリ使用量順に表示
まとめ - 5つのステップで対処できる!
サーバメモリ不足対策は、以下の5つのステップで対処できます:
-
free -mでメモリ全体の使用状況を把握-
availableが物理メモリの10%以下は危険信号
-
-
topでメモリを大量消費しているプロセスを特定-
Shift + Mでメモリ順ソート、RES値に注目
-
-
vmstatでスワップ発生状況を確認-
si/soが高い値なら物理メモリ不足が深刻
-
-
OOM killerの仕組みを理解して予防
- 監視アラート設定、スワップ領域の確保、OOMスコア調整
-
根本対策を実施
- コード見直し、メモリ設定最適化、物理メモリ増設検討
大切なのは、OOM killer発動前に気づくことです。そのために、日頃からメモリ監視の仕組みを整えておきましょう。
初心者のうちは、これらのコマンドを実際に手を動かして試すことが重要です。ハンズオンラボでは、実際のサーバ環境でメモリ監視を体験できる実習を提供しています。一緒に学びませんか?
一緒に学びませんか? ハンズオンラボで実践しよう!
私たちハンズオンラボでは、今回紹介したようなサーバメモリ監視・障害対応を実機で体験できる実習を定期開催しています。
✅ 完全ハンズオン形式: 実際のLinuxサーバでコマンドを実行
✅ 現役エンジニアが伴走: 10年以上の経験を持つメンバーが質問に対応
✅ 初心者大歓迎: 「コマンド初めて」でもOK!丁寧にサポートします
✅ 仲間ができる: 同じ悩みを持つエンジニア仲間と交流
「座学だけじゃ身につかない」「実務で使える監視スキルを習得したい」そんな方は、ぜひ一度遊びに来てください!
📍 connpassページ: [https://zeki-chan-lab.connpass.com/]
次回開催情報や過去の実習内容もご覧いただけます。お待ちしています!