🧠
概念 #システムパフォーマンス #Brendan Gregg #Linux #SRE #読書ノート #メモリ #OOM 📚 詳解 システム・パフォーマンス

詳解 システム・パフォーマンス - 第7章:メモリ分析

Linuxメモリ管理の仕組み・OOM・スワップ・ページキャッシュ・メモリリーク検出まで。free/vmstat/pmap/valgrind/memleak の実践的な使い方。

Linux のメモリ管理の基本

重要な概念

概念説明
ページキャッシュディスクデータを RAM にキャッシュ。フリーメモリが余れば使う
スワップRAM 不足時にディスクへページを追い出す。激遅になる
OOM Killerメモリが完全に枯渇したらカーネルがプロセスを強制終了
VSZ(仮想メモリ)プロセスが要求した仮想アドレス空間の合計(実際には使っていない部分も含む)
RSS(常駐メモリ)実際に物理メモリに載っているページ
PSS共有ライブラリを均等割りした実質的なメモリ使用量

メモリの分類

物理メモリ(RAM)
├── カーネルメモリ(カーネル自身が使用)
└── ユーザーメモリ
    ├── アプリケーション(ヒープ・スタック・mmap)
    └── ページキャッシュ(ファイルキャッシュ・バッファ)
        ↑ フリーメモリが余れば自動的に使われ、必要なら解放される

基本確認コマンド

free コマンドの正しい読み方

free -h
#              total    used    free   shared  buff/cache  available
# Mem:          16Gi    4.0Gi   2.0Gi  500Mi    10Gi        11Gi
# Swap:          2Gi      0     2Gi

# ポイント:
# - "free" が少なくても問題ない(キャッシュとして使われている)
# - "available" が実際に使えるメモリ(キャッシュを解放すれば使える分を含む)
# - available < total の 10% → 警戒ライン
# - Swap used > 0 → メモリプレッシャーが発生している

スワッピングの確認

# スワッピングが起きているか(si=スワップイン、so=スワップアウト)
vmstat 1 5
# si/so > 0 → スワッピング発生。アプリが激遅になっているはず

# スワップ使用量の推移を追う
sar -S 1 10
# kbswpused が増加傾向 → どんどんスワップを使い始めている

# スワップを最も使っているプロセス
for pid in /proc/[0-9]*/status; do
  awk '/VmSwap/{print FILENAME": "$2" "$3}' $pid
done 2>/dev/null | sort -t: -k2 -rn | head -10

メモリ詳細

# カーネルのメモリ詳細(元データ)
cat /proc/meminfo
# MemTotal, MemFree, MemAvailable
# Buffers: ブロックデバイスのバッファ
# Cached: ページキャッシュ
# SwapCached: スワップに追い出してキャッシュにも残っているページ
# AnonPages: 匿名マッピング(ヒープ等)
# Shmem: 共有メモリ

# ページングの詳細
sar -B 1 5
# pgpgin/s: ディスクからページを読み込んだ回数(スワップイン含む)
# pgpgout/s: ディスクへページを書き出した回数
# majflt/s: メジャーページフォルト(ディスクI/Oが必要) → 高いとメモリ不足
# minflt/s: マイナーページフォルト(すでにキャッシュにある)

プロセス別のメモリ使用量

# メモリ使用量でソート(上位プロセス)
ps aux | sort -k4 -rn | head -10
# RSS 列(KB)が実際の物理メモリ使用量

# より詳細な情報
ps -eo pid,ppid,user,%mem,vsz,rss,comm --sort=-%mem | head -20

# プロセスのメモリセグメント詳細
pmap -x <PID>
# Address    Kbytes    RSS    Dirty  Mode  Mapping
# 00400000      100    100        0  r-x-- myapp    ← text(コード)
# 00800000       10     10       10  rw--- myapp    ← data
# 019b0000     1024   1024     1024  rw---          ← heap(growsup)
# 7f1234...    2048   1024        0  r-x-- libc.so  ← 共有ライブラリ

# heap の大きさを確認(メモリリークの兆候)
pmap -x <PID> | grep "\[heap\]"

メモリリーク検出

症状

# プロセスの RSS が時間とともに増え続けていないか確認
watch -n 5 'ps -p <PID> -o pid,rss,vsz,comm'
# RSS が増加し続け、かつプロセスを再起動すると正常に戻る → メモリリークの可能性

memleak(BCC tool):本番向け

# 指定プロセスのメモリ割り当てを追跡(60秒後にリークを報告)
sudo memleak -p <PID> -a 10
# -a 10: 上位10スタックを表示

# 出力例:
# [0x7f...] malloc+0x...
# [0x400...] cache_add+0x...  ← キャッシュに追加しているが削除していない
# Total bytes: 52428800 (50 MB)

Valgrind:開発環境向け

# メモリリーク検出(本番では使わない ― 20〜30倍遅くなる)
valgrind --leak-check=full --show-leak-kinds=all ./myapp

# 出力例:
# LEAK SUMMARY:
#   definitely lost: 1,024 bytes in 10 blocks  ← 確実なリーク
#   indirectly lost: 512 bytes in 5 blocks
#   possibly lost: 256 bytes in 2 blocks
#   still reachable: 4,096 bytes in 1 blocks    ← 到達可能(許容範囲)

OOM(Out of Memory)の対処

OOM の検出

# OOM Killer が発動したか確認
dmesg | grep -i "out of memory"
dmesg | grep -i "oom-killer"
# 出力例:
# kernel: Out of memory: Kill process 12345 (java) score 900 or sacrifice child.
# kernel: Killed process 12345 (java) total-vm:8388608kB, anon-rss:7340032kB

# systemd ジャーナルから確認
journalctl -k | grep -i "out of memory"

OOM が起きた場合の調査

# 1. どのプロセスが殺されたか
dmesg | grep "Killed process"

# 2. 当時のメモリ使用量を確認
dmesg | grep -A 20 "out of memory"
# OOM時のプロセスごとのメモリ使用量が出力される

# 3. スコアの確認(高いほど OOM killer に狙われやすい)
cat /proc/<PID>/oom_score
cat /proc/<PID>/oom_score_adj  # -1000(保護)〜1000(積極的に殺す)

# 4. OOM を起こしたプロセスの保護(緊急措置)
echo -1000 > /proc/<PID>/oom_score_adj  # このプロセスを保護

チューニング

スワップ設定

# スワップの積極度を下げる(メモリに余裕があるうちはスワップしない)
sysctl vm.swappiness=10  # デフォルト60 → 10に下げる(0は非推奨)
# 永続化:
echo "vm.swappiness=10" >> /etc/sysctl.conf

# スワップを無効化(メモリが十分な環境)
swapoff -a

大きなページ(HugePage)

# HugePage の使用状況確認(DB等で効果的)
cat /proc/meminfo | grep -i huge
# HugePages_Total: 1024
# HugePages_Free: 0   ← 全部使用中

# Transparent HugePage の状態
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never

メモリ問題のチェックリスト

□ free -h で available を確認(10%以下で警戒)
□ vmstat 1 で si/so 列を確認(スワッピング発生?)
□ dmesg で OOM Killer の発動を確認
□ ps で RSS が増加し続けているプロセスがないか確認
□ pmap で heap のサイズを確認
□ sar -B でメジャーページフォルト数を確認
□ vm.swappiness の設定値を確認(高すぎないか)

出典: 詳解 システム・パフォーマンス 第2版 Brendan Gregg著