デマンドページング

# プロセスへの新規メモリ割り当ての流れ
* プロセスは、システムコールの呼び出しによって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の出力の２列目が獲得済み物理メモリのサイズ、３、４列目の合計がページフォールトの数である。実行中この両方大きくなっている。

# 出典
https://gihyo.jp/book/2022/978-4-297-13148-7

# 感想
プロセスが実行されるたびにページフォールトが発生したり、カーネルがメモリ状況をうまくやってくれていることを少し実感できた気がする。
まだまだな