Carpe Diem

備忘録

VSZ, RSS(anonymous, file)の理解を深める

背景

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-vmanon-rssfile-rssshmem-rssといった単語が出てくるのでそれぞれの違いを説明していきます。

仮想メモリ

仮想メモリはメインメモリ(RAM)の抽象概念で、プロセスとカーネルにほぼ無限(64bitOSだと約16,000PB)のアドレス空間を提供します。

これにより各プロセスとカーネルは競合を気にすることなく専用のアドレス空間を利用できます。

上図のように仮想メモリはメインメモリ(物理メモリ、RAM)やストレージデバイス(ディスク)へマッピングされます。カーネルはできる限りアクティブなデータをメインメモリの方に残そうとします。

メモリの状態遷移

仮想メモリはメインメモリを無駄に使わないよう、プロセスが仮想メモリを確保してもすぐにメインメモリにマッピングはしません。

以下がその状態遷移図です。

malloc仮想メモリを確保(アロケート)しただけではRSS(物理メモリへマッピングしたサイズ)は増えず、writeして初めて増えるという流れが以下の記事で分かりやすく説明されています。

nopipi.hatenablog.com

先程の状態遷移と合わせるとこんな感じです。

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します。

golangとDockerとOOM — KaoriYa

total-vm、anon-rss、file-rss、shmem-rssとは

最初の背景に戻ってtotal-vmanon-rssfile-rssshmem-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-rssanon-rssになり、それに合わせてメモリの増強であったり実装の改善をする必要があります。

参考