背景
KubernetesでPodがOOM Killされた際には以下のようなログが発生します。
Memory cgroup out of memory: Kill process 9130 (XXXX) score 1592 or sacrifice child Killed process 9130 (XXXX) total-vm:423008kB, anon-rss:122484kB, file-rss:33792kB, shmem-rss:0kB
その中でtotal-vm
、anon-rss
、file-rss
、shmem-rss
といった単語が出てくるのでそれぞれの違いを説明していきます。
仮想メモリ
仮想メモリはメインメモリ(RAM)の抽象概念で、プロセスとカーネルにほぼ無限(64bitOSだと約16,000PB)のアドレス空間を提供します。
これにより各プロセスとカーネルは競合を気にすることなく専用のアドレス空間を利用できます。
上図のように仮想メモリはメインメモリ(物理メモリ、RAM)やストレージデバイス(ディスク)へマッピングされます。カーネルはできる限りアクティブなデータをメインメモリの方に残そうとします。
メモリの状態遷移
仮想メモリはメインメモリを無駄に使わないよう、プロセスが仮想メモリを確保してもすぐにメインメモリにマッピングはしません。
以下がその状態遷移図です。
mallocで仮想メモリを確保(アロケート)しただけではRSS(物理メモリへマッピングしたサイズ)は増えず、writeして初めて増えるという流れが以下の記事で分かりやすく説明されています。
先程の状態遷移と合わせるとこんな感じです。
AnonymousとFile-backed
Anonymous
ファイルシステム位置やパス名を持たないプライベートデータ(ヒープ、スタック)のメモリです。
Anonymous pageのページアウトは必ず物理スワップデバイスへの書き込みが必要となるため、パフォーマンスが悪化します。
File-backed
mmap()
を使ったファイルのメモリへのマッピングで発生した分です。
ディスクからメモリに読み込んだファイルなど場合に発生し、その内容をディスクに書き戻せば解放することができます。
/proc/meminfo
/proc/meminfo
にAnonymous, File-backedの使用量が表示されます。
$ cat /proc/meminfo MemTotal: 985392 kB MemFree: 511608 kB MemAvailable: 754608 kB Buffers: 17592 kB Cached: 282312 kB SwapCached: 0 kB Active: 98564 kB Inactive: 252068 kB Active(anon): 1048 kB Inactive(anon): 58184 kB Active(file): 97516 kB Inactive(file): 193884 kB Unevictable: 26320 kB Mlocked: 26320 kB SwapTotal: 0 kB SwapFree: 0 kB Dirty: 2076 kB Writeback: 0 kB AnonPages: 77084 kB Mapped: 53900 kB Shmem: 1116 kB KReclaimable: 27104 kB Slab: 57436 kB SReclaimable: 27104 kB SUnreclaim: 30332 kB KernelStack: 1740 kB PageTables: 1728 kB NFS_Unstable: 0 kB Bounce: 0 kB WritebackTmp: 0 kB CommitLimit: 492696 kB Committed_AS: 287028 kB VmallocTotal: 133143592960 kB VmallocUsed: 9132 kB VmallocChunk: 0 kB Percpu: 444 kB HardwareCorrupted: 0 kB AnonHugePages: 0 kB ShmemHugePages: 0 kB ShmemPmdMapped: 0 kB FileHugePages: 0 kB FilePmdMapped: 0 kB CmaTotal: 32768 kB CmaFree: 32384 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB Hugetlb: 0 kB
システムやカーネルのバージョンによって振る舞いが異なることがあるため、ズレが生じることもありますが大まかに以下のような式が成り立ちます。
File-backed
Buffers + Cached = Active(file) + Inactive(file) + Shmem
Anonymous
Active(anon) + Inactive(anon) = Shmem + AnonPages
なのでこれらを図示すると以下のようになります。
メモリの使用状況に対する用語
前提知識が付いた上でVSS, USS, PSS, RSSといった用語を説明します。
用語 | 説明 |
---|---|
VSS(VSZ) (virtual set size) |
プロセスが使用する仮想メモリの総量 プロセスのコード、データ、スタック、ヒープ、および共有ライブラリやマッピングされたファイルなどのメモリが含まれる |
USS (unique set size) |
プロセスによって専用に使用されている物理メモリの量 そのプロセスにのみ属するプライベートページの合計 プロセスを終了させると解放されるメモリ量 |
PSS (proportional set size) |
USS + 共有メモリを使用している全プロセス間で均等に分割した量 全プロセスを考慮した上でのメモリ使用割合を公平に評価する際に利用する |
RSS (resident set size) |
プロセスが物理メモリ上に実際に保持しているメモリの量 プロセスのプライベートページと共有メモリの両方が含まれる |
図で表すと以下です。
DockerはRSSを見てる
以下のブログで詳細が解説されていますが、DockerはRSSベースでOOM Killします。
total-vm、anon-rss、file-rss、shmem-rssとは
最初の背景に戻ってtotal-vm
、anon-rss
、file-rss
、shmem-rss
について説明すると、以下のようなまとめになります。
用語 | 説明 |
---|---|
total-vm | プロセスのVSS(VSZ) つまりプロセスが使用する仮想メモリの総量 |
anon-rss | Anonymousページが使用している物理メモリサイズ |
file-rss | File-backedページが使用している物理メモリサイズ |
shmem-rss | 共有メモリが使用している物理メモリサイズ |
なのでKubernetesのOOM Killによるログ
Memory cgroup out of memory: Kill process 9130 (XXXX) score 1592 or sacrifice child Killed process 9130 (XXXX) total-vm:423008kB, anon-rss:122484kB, file-rss:33792kB, shmem-rss:0kB
で見るべき部分は基本的にはanon-rss
、anon-rss
になり、それに合わせてメモリの増強であったり実装の改善をする必要があります。