プロセスへの新規メモリ割り当ての流れ
- プロセスは、システムコールの呼び出しによってXXバイトのメモリが欲しいとカーネルに依頼される
- カーネルは、システムの空きメモリからXXバイトの領域を獲得する
- 獲得したメモリ領域をプロセスの仮想アドレス空間にマップする
- 上記仮想アドレス空間の先頭アドレスをプロセスに返す
仮想アドレスの範囲を見て獲得した領域を見てみる
root@::***********:**********# go build mmap.go
root@::***********:**********# ./mmap
*** 新規メモリ領域獲得前のメモリマップ ***
00400000-004aa000 r-xp 00000000 08:05 402704 /home/vboxuser/***********/mmap
004aa000-00583000 r--p 000aa000 08:05 402704 /home/vboxuser/***********/mmap
00583000-0059a000 rw-p 00183000 08:05 402704 /home/vboxuser/***********/mmap
0059a000-005b8000 rw-p 00000000 00:00 0
c000000000-c004000000 rw-p 00000000 00:00 0
7f75ac354000-7f75ae605000 rw-p 00000000 00:00 0
7ffdf220c000-7ffdf222d000 rw-p 00000000 00:00 0 [stack]
7ffdf2314000-7ffdf2318000 r--p 00000000 00:00 0 [vvar]
7ffdf2318000-7ffdf231a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
*** 新規メモリ領域: アドレス = 0x7f756c354000, サイズ = 0x40000000 ***
*** 新規メモリ領域獲得後のメモリマップ ***
00400000-004aa000 r-xp 00000000 08:05 402704 /home/vboxuser/***********/mmap
004aa000-00583000 r--p 000aa000 08:05 402704 /home/vboxuser/***********/mmap
00583000-0059a000 rw-p 00183000 08:05 402704 /home/vboxuser/***********/mmap
0059a000-005b8000 rw-p 00000000 00:00 0
c000000000-c004000000 rw-p 00000000 00:00 0
7f756c354000-7f75ae605000 rw-p 00000000 00:00 0
7ffdf220c000-7ffdf222d000 rw-p 00000000 00:00 0 [stack]
7ffdf2314000-7ffdf2318000 r--p 00000000 00:00 0 [vvar]
7ffdf2318000-7ffdf231a000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]
デマンドページング
mmap()システムコールの呼び出し直後、新規メモリ領域に対応する物理メモリはまだ存在しません
。その代わり、新規獲得領域の中の各ページに最初にアクセスしたときに物理メモリを割り当てる
のです。その仕組みをデマンドページングと呼びます。デマンドページングを実現するためにメモリ管理システムは、ページごとに「ページに対応する物理メモリが割り当て済みか」
という状態を持っています
...
物理メモリに割り当てる流れ
- プロセスがページにアクセス
- ページフォールト発生
- カーネルのページフォールトハンドラが動作して、ページに対応する物理メモリを割り当てる。
ページフォールトハンドラは、ページテーブルエントリが存在しないページにアクセスした場合は、プロセスにSIGSEGVを送る一方で、ページテーブルエントリが存在するものの、対応する物理メモリが割り当てられない場合は新規メモリを割り当てる
、というように分岐させているのです。
気づき
ページフォールトハンドラはページテーブルエントリが存在するかしないか関わらず動くだな
ページごとに問い合わせするんだな
ページごとにするから断片化しててもアクセスできるのか。
ページフォールトの問い合わせて獲得する流れを見てみる
root@::***********:**********# ./demand-paging.py
18:00:30: 新規メモリ領域獲得前。Enterキーを押すと100MiBの新規メモリ領域を獲得します:
18:00:40: 新規メモリ領域を獲得しました。Enterキーを押すと1秒に10MiBづつ、合計100MiBの新規メモリ領域にアクセスします:
18:00:40: 10 MiBアクセスしました
18:00:41: 20 MiBアクセスしました
18:00:42: 30 MiBアクセスしました
18:00:43: 40 MiBアクセスしました
18:00:44: 50 MiBアクセスしました
18:00:45: 60 MiBアクセスしました
18:00:46: 70 MiBアクセスしました
18:00:47: 80 MiBアクセスしました
18:00:48: 90 MiBアクセスしました
18:00:49: 新規獲得したメモリ領域のすべてのアクセスしました。Enterキーを押すと終了します:
root@::***********:**********# sar -r 1
Linux 5.15.0-107-generic (***********) 2024年05月21日 _x86_64_ (1 CPU)
18時00分38秒 kbmemfree kbavail kbmemused %memused kbbuffers kbcached kbcommit %commit kbactive kbinact kbdirty
18時00分39秒 1476336 2662668 930548 23.81 49288 1328312 4254124 83.44 535396 1616364 344
18時00分40秒 1476336 2662668 930548 23.81 49288 1328312 4356548 85.45 535396 1616416 352
18時00分41秒 1476336 2662668 930548 23.81 49288 1328312 4356548 85.45 535396 1626616 60
18時00分42秒 1476336 2662668 930548 23.81 49296 1328304 4356548 85.45 535396 1636864 40
18時00分43秒 1476336 2662676 930540 23.81 49296 1328312 4356548 85.45 535404 1647116 72
18時00分44秒 1476336 2662676 930540 23.81 49296 1328312 4356548 85.45 535404 1657376 72
18時00分45秒 1476084 2662424 930928 23.82 49296 1328176 4356320 85.45 535404 1667420 72
18時00分46秒 1476084 2662424 930928 23.82 49296 1328176 4356320 85.45 535404 1677620 72
18時00分47秒 1472808 2659148 934204 23.91 49296 1328176 4356320 85.45 535404 1687860 8
18時00分48秒 1462476 2648816 944536 24.17 49296 1328176 4356320 85.45 535404 1698120 8
18時00分49秒 1452144 2638484 954868 24.43 49296 1328176 4356320 85.45 535404 1708380 8
18時00分50秒 1442064 2628404 964948 24.69 49296 1328176 4356356 85.45 535404 1718652 8
18時00分51秒 1477100 2663560 929784 23.79 49296 1328304 4250036 83.36 535436 1612760 156
18時00分52秒 1476860 2663328 930020 23.80 49296 1328308 4250060 83.36 535436 1612912 156
18時00分53秒 1476860 2663328 930020 23.80 49296 1328308 4250060 83.36 535436 1612896 156
18時00分54秒 1476860 2663328 930020 23.80 49296 1328308 4250060 83.36 535436 1612896 156
^C
平均値: 1471710 2658079 935220 23.93 49294 1328259 4323440 84.80 535410 1650642 109
kbmemused
Amount of used memory in kilobytes (calculated as total
installed memory - kbmemfree - kbbuffers - kbcached -
kbslab).
% memused
Percentage fo used memory
kbinact
Amount of inactive memory in kilobytes (memory which has been less
recently used. It is more eligible to be re- claimed for other purposes).
kbslab
Amount of memory in kilobytes used by the kernel to
cache data structures for its own use.
和訳
kbmemused
使用メモリ量(キロバイト単位)。 kbmemfree-kbbuffers-kbcached-kbslab)。
kbinact
キロバイト単位の非アクティブメモリー量(最近あまり使用されていないメモリー。他の目的で再クレームされる可能性が高い)。
出典
deepl
気づき
参考書通りにkbmemusedが100MB増えなかった。しかしプロセス使用中の時間帯だけ%memusedが上り、kbmemfreeが下がっていたので実行されていたと考える。
kbinactが100MBだけ増えていた。
slabが関係しているかもしれないが、取得することができなかった。
まぁpythonのコード読めればよかったけどな
システム全体のページフォールの数とそれに伴う物理メモリのサイズを取得を見てみる
sar -B
コマンドによってシステム全体のページフォールト発生回数を確認できます
root@::***********:**********# ./demand-paging.py
18:07:07: 新規メモリ領域獲得前。Enterキーを押すと100MiBの新規メモリ領域を獲得します:
18:07:35: 新規メモリ領域を獲得しました。Enterキーを押すと1秒に10MiBづつ、合計100MiBの新規メモリ領域にアクセスします:
18:07:36: 10 MiBアクセスしました
18:07:37: 20 MiBアクセスしました
18:07:38: 30 MiBアクセスしました
18:07:39: 40 MiBアクセスしました
18:07:40: 50 MiBアクセスしました
18:07:41: 60 MiBアクセスしました
18:07:42: 70 MiBアクセスしました
18:07:43: 80 MiBアクセスしました
18:07:44: 90 MiBアクセスしました
18:07:45: 新規獲得したメモリ領域のすべてのアクセスしました。Enterキーを押すと終了します:
root@::***********:**********# sar -B 1
Linux 5.15.0-107-generic (***********) 2024年05月21日 _x86_64_ (1 CPU)
18時07分33秒 pgpgin/s pgpgout/s fault/s majflt/s pgfree/s pgscank/s pgscand/s pgsteal/s %vmeff
18時07分34秒 0.00 0.00 3.00 0.00 119.00 0.00 0.00 0.00 0.00
18時07分35秒 0.00 16.00 6.00 0.00 21.00 0.00 0.00 0.00 0.00
18時07分36秒 0.00 0.00 2567.00 0.00 28.00 0.00 0.00 0.00 0.00
18時07分37秒 0.00 229.70 2536.63 0.00 47.52 0.00 0.00 0.00 0.00
18時07分38秒 0.00 0.00 2571.00 0.00 53.00 0.00 0.00 0.00 0.00
18時07分39秒 0.00 0.00 2565.00 0.00 98.00 0.00 0.00 0.00 0.00
18時07分40秒 0.00 24.00 2710.00 0.00 187.00 0.00 0.00 0.00 0.00
18時07分41秒 0.00 0.00 2541.58 0.00 41.58 0.00 0.00 0.00 0.00
18時07分42秒 0.00 0.00 2560.00 0.00 29.00 0.00 0.00 0.00 0.00
18時07分43秒 0.00 0.00 2686.00 0.00 35.00 0.00 0.00 0.00 0.00
18時07分44秒 0.00 0.00 2560.00 0.00 12.00 0.00 0.00 0.00 0.00
18時07分45秒 0.00 0.00 2560.00 0.00 13.00 0.00 0.00 0.00 0.00
18時07分46秒 0.00 16.00 55.00 0.00 26631.00 0.00 0.00 0.00 0.00
18時07分47秒 0.00 0.00 21.00 0.00 119.00 0.00 0.00 0.00 0.00
18時07分48秒 0.00 0.00 0.00 0.00 25.00 0.00 0.00 0.00 0.00
^C
平均値: 0.00 19.17 1730.56 0.00 1828.23 0.00 0.00 0.00 0.00
fault/s
Number of page faults (major + minor) made by the system
per second. This is not a count of page faults that
generate I/O, because some page faults can be resolved
without I/O.
和訳
fault/s
システムが1秒間に発生させたページフォルトの数(メジャー+マイナー
数。 ページフォールトの中にはI/Oなしで解決できるものもあるため、これはI/Oを生成するページフォールトのカウントではない。
出典
deepl
気づき
これはI/Oを生成するページフォールトのカウントではない。と書かれていたので、fault/sはページフォールトの回数では無いと思う。しかし値が実行中だけ多くなっているのでページフォールが起こっていることがわかる。
プロセス単体のページフォールの数とそれに伴う物理メモリのサイズを取得を見る
root@::***********:**********# ./demand-paging.py
00:09:49: 新規メモリ領域獲得前。Enterキーを押すと100MiBの新規メモリ領域を獲得します:
00:09:58: 新規メモリ領域を獲得しました。Enterキーを押すと1秒に10MiBづつ、合計100MiBの新規メモリ領域にアクセスします:
00:10:00: 10 MiBアクセスしました
00:10:01: 20 MiBアクセスしました
00:10:02: 30 MiBアクセスしました
00:10:03: 40 MiBアクセスしました
00:10:04: 50 MiBアクセスしました
00:10:05: 60 MiBアクセスしました
00:10:06: 70 MiBアクセスしました
00:10:07: 80 MiBアクセスしました
00:10:08: 90 MiBアクセスしました
00:10:09: 新規獲得したメモリ領域のすべてのアクセスしました。Enterキーを押すと終了します:
root@::***********:**********# ./capture.sh
2024年 5月 22日 水曜日 00:09:56 JST: 16936 9288 3 1084
2024年 5月 22日 水曜日 00:09:57 JST: 16936 9288 3 1084
2024年 5月 22日 水曜日 00:09:58 JST: 16936 9288 3 1084
2024年 5月 22日 水曜日 00:09:59 JST: 119336 9288 3 1084
2024年 5月 22日 水曜日 00:10:00 JST: 119336 9288 3 1084
2024年 5月 22日 水曜日 00:10:01 JST: 119336 19628 3 3646
2024年 5月 22日 水曜日 00:10:02 JST: 119336 29984 3 6206
2024年 5月 22日 水曜日 00:10:03 JST: 119336 40280 3 8766
2024年 5月 22日 水曜日 00:10:04 JST: 119336 50576 3 11326
2024年 5月 22日 水曜日 00:10:05 JST: 119336 70904 3 16446
2024年 5月 22日 水曜日 00:10:06 JST: 119336 81200 3 19006
2024年 5月 22日 水曜日 00:10:07 JST: 119336 91496 3 21566
2024年 5月 22日 水曜日 00:10:08 JST: 119336 101528 3 24126
2024年 5月 22日 水曜日 00:10:09 JST: 119336 111824 3 26685
2024年 5月 22日 水曜日 00:10:10 JST: 119336 111824 3 26685
2024年 5月 22日 水曜日 00:10:11 JST: demand-paging.pyプロセスは終了しました。
気づき
このcapture.shの出力の2列目が獲得済み物理メモリのサイズ、3、4列目の合計がページフォールトの数である。実行中この両方大きくなっている。
出典
感想
プロセスが実行されるたびにページフォールトが発生したり、カーネルがメモリ状況をうまくやってくれていることを少し実感できた気がする。
まだまだな