Linuxはメモリを可能な限り使う実装。

メモリが空いていれば、それはキャッシュやバッファーに使う。
bufferは、ファイルに対して書き込みが完了していない内容。dirty cacheとも言う。
cacheは、同期が完了しているファイルの内容。

プログラムの読み書きは、低レベルのI/Oを発行しない限り、bufferになり、cacheになる。これはLinuxカーネルがコントロールし、特に意識する必要はない。

Linuxのパフォーマンスの高さの理由のひとつとして、このメモリ利用が巧みである、ということが挙げられる。
Windowsはメモリを常に余らせてしまうが、Linuxは長期稼働していればいずれメモリのfreeは0になる。

このcacheは重要だ。なにせ、ディスクはメモリの100倍は遅い。いちいちディスクに対して読み書きしていたら、ものすごくストレスフルな環境ができあがる。

ユーザー空間のメモリはFile-backedとAnonymousがある。
File-backedはファイルと一致するもので、ファイルに書き出してしまえば解放することができる。
一方、Anonymousはプログラムが使っている内容であり、解放するためにはプロセスを殺すか(最終手段)、Swapに追い出すしかない。

File-backedはBuffers + Cachedだが、

Buffer = Active(file)
Cached = Inactive(file) + Shmem
File-backed = Buffer + Cache

ということになる。

こうした理由から、Memfreeがないからといってメモリ不足ではないが、「プログラムが空中で確保しているAnon分だけメモリがあればいい!」とか思うのは間違っている。
それだけあれば動くが、恐ろしくストレスが増す。

さて、ここで問題が発生した。

メモリはあればあるだけいいというのはあるものの、ずっと余裕がある場合は間違いなくそれ以上積んでもパフォーマンス向上にはつながらない。
では実際にメモリはどれくらい積めば、パフォーマンス向上が頭打ちになるのか。

最後にアクセスされたのがはるか昔で、いつでも解放できるメモリは空きも同然だ。だが、Linuxは特に不足しなければそれはそのままにする。
今の状態で十分なのか。それとも、もっと積めばパフォーマンスが向上するのか。さらに重い処理をしても余裕はあるのか。tmpfsにどれくらいファイルをおけるのか。
そして、新しいマシンを組む時にメモリはどれくらい必要なのか。

気になる。すごく。

ひとつの考え方としては、so(Swap Out)もsi(Swap In)もずーっと0のままであれば、それはあまりにも余裕がありすぎて、Swapを使うかどうかを判断する必要自体が全く無い、という状態なので、「ものすごく余っているから増やす必要はない」と考えていいが、

それでは気持ち悪くないか。

古いキャッシュだけ捨てられればわかるのになぁ、なんか方法ないかなぁ、と思って調べていたら、見つけた。

/proc/meminfoだ。

これをみると

MemTotal:       12291120 kB
MemFree:          568720 kB
MemAvailable:    8536348 kB
Buffers:          196976 kB
Cached:          7606960 kB
SwapCached:            0 kB
Active:          6458348 kB
Inactive:        4584444 kB
Active(anon):    3052444 kB
Inactive(anon):   298720 kB
Active(file):    3405904 kB
Inactive(file):  4285724 kB
Unevictable:       49344 kB
Mlocked:           49408 kB
SwapTotal:       4034556 kB
SwapFree:        4034556 kB
Dirty:               964 kB
Writeback:             0 kB
AnonPages:       3288328 kB
Mapped:           703892 kB
Shmem:             72480 kB
Slab:             390816 kB
SReclaimable:     328332 kB
SUnreclaim:        62484 kB
KernelStack:       12096 kB
PageTables:        48484 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    10180116 kB
Committed_AS:    8082496 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      173492 kB
VmallocChunk:   34359488508 kB
HardwareCorrupted:     0 kB
AnonHugePages:   1734656 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:     1635988 kB
DirectMap2M:    10930176 kB

のように表示される。

答ががっつり書いてあった。

Activeが最近アクセスされた領域、Inactiveがいつでも解放できるとマークされている領域。「はるか昔のいらないキャッシュ」はInactive(file)だ。

つまり、「余裕」とみなせるのは

Memfree + Inactive

ということになる。空き領域と、使われていない領域だ。
基本的にLinuxのメモリー確保は

  1. 空いているなら確保
  2. 使われていないのなら捨てて確保
  3. 使われているのなら、Active(file)の領域を(Dirtyならsyncしてから)解放するか、もちしくSwap

という順で行う。よって、Free+Inactiveが常に潤沢にあるのであれば、メモリ容量によるパフォーマンス低下は起こらない。

このことからメモリの追加に意味があるのか、そもそもメモリはどれくらい必要なのか、を推測する術が見つかった。

MemTotal - ( MemFree + Inactive )

長期に渡り活発に使用して常に保たれるこの量が、余裕の量だ。
重い処理をした場合でも、その重い処理がその量以上に使おうとしなければ問題ない。

ということで見ると、だいたい5Gくらい余裕があるわけで、となると使っているのは7GBくらいか。
実感としては、起動時に3GB近い(Manjaro LinuxでCinnamon。Plasma Workspaceだともうちょっと多い)ので、間違いなく4GBなければ「まともに」動かないが(軽量環境を使う必要がある)、当然ながら4GBだとすぐに枯渇する。4GBで足りないのはわかるが、では6GBなのか、8GBなのかという話になる。

感覚的には、だいたい6GBくらいは使うという印象がある。
稼働時間が浅いうちの値がそれぐらいで伸びなくなるからだ。
よって、6GBだと不足する可能性が高い。

8GBで十分かどうかがよくわからなかったのだが、これを見ると、Swapがちゃんと確保されていれば、若干のパフォーマンス低下はあるものの、ちゃんと動きそうだ。
ただし、tmpfsを使うと明らかにすぐ不足するので、tmpfsの積極利用は控えたほうがいい。

12GB(私と同じ2×2+4×2か、あるいは2×6)ならば、おおよそ問題はないが、tmpfsにDVDイメージを置くとswapされる可能性がある。
また、ビルド時にtmpfsに大きなファイルを起き、ビルド自体が重いときついかもしれない。ただし、12GBでかなり重いopenjdk8-infinalityとMozc-UTをビルドしたが、問題なかった。

16GB(4×4か8×2)ならばかなり余裕があり、ほとんど気にする必要はなくなる。

というのが、今回調べた結論だ。

今回はenkai00さんのブログエントリを全面的に参考にさせていただいた。非常に有用な記事だった。ありがとうございました。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください