CLOVER🍀

That was when it all began.

Linuxでメモリの断片化に関する情報を見る?

これは、なにをしたくて書いたもの?

Linuxで、メモリの断片化に関する情報が見れるようなので、少し調べてみました。

情報は、このあたりをベースにしています。

The /proc Filesystem — The Linux Kernel documentation

proc(5) - Linux manual page

Ubuntu Manpage: proc - プロセスの情報を含む擬似ファイルシステム

ちなみに、今回は断片化の様子を確認したという話ではなく、あくまで情報の取得方法を見ているだけです。

環境

今回の確認環境は、こちら。Ubuntu Linux 20.04 LTSです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 20.04.3 LTS
Release:    20.04
Codename:   focal


$ uname -srvmpio
Linux 5.4.0-81-generic #91-Ubuntu SMP Thu Jul 15 19:09:17 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

4 CPU、メモリ8Gの構成です。

$ grep ^processor /proc/cpuinfo
processor   : 0
processor   : 1
processor   : 2
processor   : 3


$ grep ^MemTotal /proc/meminfo
MemTotal:        8054420 kB

/proc/buddyinfo、/proc/pagetypeinfo、/sys/kernel/debug/extfrag/unusable_index

メモリの断片化について確認するには、

  • /proc/buddyinfo
  • /proc/pagetypeinfo
  • /sys/kernel/debug/extfrag/unusable_index

あたりの情報を見ればよさそうです。

まずは、/proc/buddyinfoから。

$ cat /proc/buddyinfo 
Node 0, zone      DMA      1      0      0      1      2      1      1      0      1      1      3 
Node 0, zone    DMA32      3      3      1      1      1      0      2      3      2      3    745 
Node 0, zone   Normal   1831    712    379    292    304     35     10      7      2     19   1016

/proc/buddyinfoでは、メモリの断片化に関する情報を見ることができます。これは、OSやCPUがメモリを扱う単位である
ページを管理するために使う、バディアロケーターの統計情報です。

Documentation for /proc/sys/kernel/ / shmall

読み方ですが、各ゾーン(この例ではDMA、DMA32、Normal)で使用可能なチャンクの数が表示されています。

全部で11個あり、以下の計算式で算出できます。

(2 ^ order)* PAGE_SIZE

ここで、ページサイズは今回の環境では4KBでした。

$ getconf PAGE_SIZE
4096

つまり、4KB、8KB、16KB、32KB、64KB、128KB、256KB、512KB、1MB、2MB、4MBという並びになります。

たとえば、この例でDMAというゾーンであれば、4KBのチャンクが1つ、32KBのチャンクが1つ、64KBのチャンクが
1つ…4MBのチャンクが4つ、みたいな読み方になります。

Node 0, zone      DMA      1      0      0      1      2      1      1      0      1      1      3

Normalというゾーンであれば、4KBのチャンクが1831、4MBのチャンクが1016あることになります。4MBのチャンクだけで、
4Gのメモリがあることになります。

Node 0, zone   Normal   1831    712    379    292    304     35     10      7      2     19   1016

ここで、右にある大きなサイズのチャンクが小さくなっており、左にある小さなサイズのチャンクが多くなっている場合は
断片化が進んでいる(小さなチャンクしか残っていない)ことを示します。

どんなゾーンがあるかは、/proc/zoneinfoで確認できます。

$ grep '^Node' /proc/zoneinfo 
Node 0, zone      DMA
Node 0, zone    DMA32
Node 0, zone   Normal
Node 0, zone  Movable
Node 0, zone   Device

Normalというのが、通常のゾーンでほとんどのメモリがここに収まります。

DMAは古くからある16MBのゾーンで、ドライバなどが使用します。

Is it time to remove ZONE_DMA? [LWN.net]

DMA32は、32ビット用に拡張されたDMAゾーンです。

ZONE_DMA32 [LWN.net]

Documentation for /proc/sys/vm/ — The Linux Kernel documentation

Normalゾーンは、こんな感じになっています。

Node 0, zone   Normal
  pages free     1065288
        min      10537
        low      13171
        high     15805
        spanned  1286144
        present  1286144
        managed  1243715
        protection: (0, 0, 0, 0, 0)
      nr_free_pages 1065288
      nr_zone_inactive_anon 462
      nr_zone_active_anon 12286
      nr_zone_inactive_file 33396
      nr_zone_active_file 89457
      nr_zone_unevictable 4616
      nr_zone_write_pending 0
      nr_mlock     4616
      nr_page_table_pages 365
      nr_kernel_stack 2096
      nr_bounce    0
      nr_zspages   0
      nr_free_cma  0
      numa_hit     737828
      numa_miss    0
      numa_foreign 0
      numa_interleave 62933
      numa_local   737828
      numa_other   0
  pagesets
    cpu: 0
              count: 319
              high:  378
              batch: 63
  vm stats threshold: 42
    cpu: 1
              count: 200
              high:  378
              batch: 63
  vm stats threshold: 42
    cpu: 2
              count: 53
              high:  378
              batch: 63
  vm stats threshold: 42
    cpu: 3
              count: 288
              high:  378
              batch: 63
  vm stats threshold: 42
  node_unreclaimable:  0
  start_pfn:           1048576

さらに詳細を/proc/pagetypeinfoで見ることができます。

$ sudo cat /proc/pagetypeinfo
Page block order: 9
Pages per block:  512

Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10 
Node    0, zone      DMA, type    Unmovable      1      0      0      1      2      1      1      0      1      0      0 
Node    0, zone      DMA, type      Movable      0      0      0      0      0      0      0      0      0      1      3 
Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone      DMA, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone      DMA, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type    Unmovable      1      0      0      0      0      0      1      1      1      1      0 
Node    0, zone    DMA32, type      Movable      2      3      1      1      1      0      1      2      1      2    745 
Node    0, zone    DMA32, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type    Unmovable    168    152     70      2      9      4      0      1      0     16     15 
Node    0, zone   Normal, type      Movable   1636    560    285    285    292     29     10      5      1      2   1001 
Node    0, zone   Normal, type  Reclaimable      3      8     23      4      3      2      0      1      1      1      0 
Node    0, zone   Normal, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 

Number of blocks type     Unmovable      Movable  Reclaimable   HighAtomic          CMA      Isolate 
Node 0, zone      DMA            1            7            0            0            0            0 
Node 0, zone    DMA32            2         1526            0            0            0            0 
Node 0, zone   Normal          106         2368           38            0            0            0

たとえば/proc/buddyinfoではDMA32ゾーンはこのような内容でしたが、

Node 0, zone    DMA32      3      3      1      1      1      0      2      3      2      3    745 

/proc/pagetypeinfoではその内訳を見ることができます。

Node    0, zone    DMA32, type    Unmovable      1      0      0      0      0      0      1      1      1      1      0 
Node    0, zone    DMA32, type      Movable      2      3      1      1      1      0      1      2      1      2    745 
Node    0, zone    DMA32, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 

Movableなどをマイグレーションタイプと呼ぶようで、それぞれ以下のような意味になるようです。

  • Unmovable … カーネルが内部的に使うもので、移行できないもの(長命)
  • Movable … ユーザープロセス用のメモリで、移行可能なもの(短命)
  • Reclaimable … ページキャッシュ、i-nodeキャッシュなど(短命)
  • HighAtomic … These are high-order allocations belonging to callers that cannot sleep or perform any IO. In practice, this is restricted to jumbo frame allocation for network receive.(短命)
  • CMA … 連続したメモリ割り当て領域
  • Isolate … 使われない?

HighAtomicは意味がよくわかりませんでした…。

ここで移行と言っているのはメモリを使用しているプロセスが認識している仮想アドレスを変えず、ページの物理的な
位置を移動できることを指します。

Page migration — The Linux Kernel documentation

参考)

Linuxメモリ管理の最先端を探る(1/2) − @IT

Group pages of related mobility together to reduce external fragmentation v28 [LWN.net]

Contiguous memory allocation for drivers [LWN.net]

A reworked contiguous memory allocator [LWN.net]

Linux memo 2020/10/17 - らるるの自宅と職場を往復する人生@それをすてるなんてとんでもない!

https://github.com/torvalds/linux/blob/v5.4/include/linux/mmzone.h#L41-L67

/proc/buddyinfoでNormalゾーンを見ると、こんな感じになっています。

Node    0, zone   Normal, type    Unmovable    168    152     70      2      9      4      0      1      0     16     15 
Node    0, zone   Normal, type      Movable   1636    560    285    285    292     29     10      5      1      2   1001 
Node    0, zone   Normal, type  Reclaimable      3      8     23      4      3      2      0      1      1      1      0 
Node    0, zone   Normal, type   HighAtomic      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type          CMA      0      0      0      0      0      0      0      0      0      0      0 
Node    0, zone   Normal, type      Isolate      0      0      0      0      0      0      0      0      0      0      0 

あとは、/sys/kernel/debug/extfrag/unusable_index。

$ sudo cat /sys/kernel/debug/extfrag/unusable_index
Node 0, zone      DMA 0.000 0.000 0.000 0.000 0.002 0.010 0.018 0.034 0.034 0.098 0.227 
Node 0, zone    DMA32 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.000 0.001 0.003 
Node 0, zone   Normal 0.000 0.001 0.003 0.004 0.006 0.011 0.012 0.012 0.013 0.014 0.023

こちらは、値が0.000に近づくほど利用可能なチャンクが多く、1.000に近づくほど利用可能なチャンクが少ないことを
表します。各ゾーンに対して11個の数字が並ぶのは、/proc/buddyinfoと同じ読み方でOKです。

ちなみに、/proc/buddyinfoなどで見ていた値を合計すると、freeや/proc/meminfoで見る"free"および"MemFree"の値と   ほぼ同じになります。

/proc/buddyinfoの実行と、ほぼ同じタイミングで取得したfree -h。

$ free -h
              total        used        free      shared  buff/cache   available
Mem:          7.7Gi       137Mi       7.0Gi       2.0Mi       561Mi       7.3Gi
Swap:         1.9Gi          0B       1.9Gi

同じく、/proc/meminfo。

$ cat /proc/meminfo
MemTotal:        8054428 kB
MemFree:         7338756 kB
MemAvailable:    7645824 kB
Buffers:           61396 kB
Cached:           440440 kB
SwapCached:            0 kB
Active:           407000 kB
Inactive:         135432 kB
Active(anon):      49156 kB
Inactive(anon):     1848 kB
Active(file):     357844 kB
Inactive(file):   133584 kB
Unevictable:       18464 kB
Mlocked:           18464 kB
SwapTotal:       1999868 kB
SwapFree:        1999868 kB
Dirty:               160 kB
Writeback:             0 kB
AnonPages:         59060 kB
Mapped:            48276 kB
Shmem:              2212 kB
KReclaimable:      73220 kB
Slab:             125560 kB
SReclaimable:      73220 kB
SUnreclaim:        52340 kB
KernelStack:        2096 kB
PageTables:         1460 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     6027080 kB
Committed_AS:     271920 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       10616 kB
VmallocChunk:          0 kB
Percpu:             2896 kB
HardwareCorrupted:     0 kB
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      128876 kB
DirectMap2M:     3966976 kB
DirectMap1G:     4194304 kB

ここで、DMAゾーンの和(4KB x 1 + ... + 4MB x 3)とDMA32ゾーンの和(4kB x 3 + ... + 4MB x 745)と
Normalゾーンの和(4KB x 1831 + ... + 4MB x 1016)を合計すると、

$ cat /proc/buddyinfo 
Node 0, zone      DMA      1      0      0      1      2      1      1      0      1      1      3 
Node 0, zone    DMA32      3      3      1      1      1      0      2      3      2      3    745 
Node 0, zone   Normal   1831    712    379    292    304     35     10      7      2     19   1016

こちらの値とほぼ等しくなります。

MemFree:         7338756 kB

vmstatでも同じですね。

だいぶ走り書きな感じですが、とりあえず今回はこんなところで…。

参考

Linux メモリ断片化 (外部フラグメンテーション) の概要と解消方法 - Qiita

Linux メモリ管理 徹底入門(カーネル編) - SIerだけど技術やりたいブログ

物理メモリのフラグメント(断片化)の状態を確認する | Redhat Enterprise Linux 4