試して理解 Linuxのしくみ
[試して理解]Linuxのしくみ ―実験と図解で学ぶOS、仮想マシン、コンテナの基礎知識【増補改訂版】 https://amzn.asia/d/1hCAO3e
絶対に死なないプロセスはuninterruptible sleepという状態になっていてps auxのSTATの一文字目がDになる
ゾンビプロセス: 終了したけど親プロセスが終了状態を得ていないプロセス
孤児プロセス: 親がwait()系システムコールの実行前に終了したプロセス
Goのプログラムは基本的にライブラリをすべて静的リンクするので共有ライブラリに依存しない
ps ajxでセッションIDやプロセスグループのPGIDが確認できる
仮想アドレス空間はプロセスごとに作られる
ページテーブルはカーネルによって作られるが、プロセスが仮想アドレスにアクセスした際に物理アドレスに変換するのはCPU
トランスペアレントヒュージページによってページテーブルのためのメモリ使用量を自動で抑えることができる
mmapシステムコールによってプロセスにメモリ領域を割り当てても即時に物理メモリが割り当てられるわけではなく、プロセスがアクセスした際に初めて物理メモリが割り当てられる。これをデマンドページングという。
fork()関数を発行した場合、子プロセスには親プロセスのページテーブルのみがコピーされ物理メモリは共有される、かつ親子ともに読み込み専用となる。どちらかのプロセスが書き込みを行おうとした際に初めて物理メモリが新規に割り当てられ内容もコピーされる、かつ書き込み可能となる。これをコピーオンライト(CoW)と呼ぶ。
このあたりは実際にメモリアクセスした際に発生したページフォールトをカーネルのページフォールトハンドラが処理することで実現している
ddコマンドにSIGUSR1を送ると進捗状況を表示してくれる
プロセス作成、スレッド作成ともにclone()システムコールが呼ばれるが、前者では仮想アドレス空間を共有せず、後者では共有する
マルチスレッドはプロセス内に複数の流れを作る
スレッドの実現方法はカーネルスレッドとユーザスレッドがあり、goroutineは後者。前者はプロセススケジューリング上で各スレッドがプロセスと同様の扱いを受けるが、後者はカーネルがスレッドを認識できないのでプロセスごとにスケジューリングされCPUが回ってきたときに各スレッドにCPUリソースを割り当てるかはスレッドライブラリの責任となる。
プロセスがデバイスファイルを操作するとカーネルの中のデバイスドライバがデバイスにアクセスする。プロセスは通常のファイルと同じようにシステムコールで操作する。
キャラクタデバイス: 読み出しと書き込みはできるがシーク操作はできない。端末やキーボード、マウスなど。
ブロックデバイス: 読み書き以外にもシークができる。HDDやSSDなど。
デバイスを直接操作する場合デバイスのレジスタにアクセスする。どのレジスタにアクセスするとどのような操作をするのかはデバイスによる。CPUのレジスタとは名前は同じだが別物
メモリマップトI/Oはカーネルの仮想アドレス空間に物理メモリだけでなくデバイスのレジスタもマップする。これによって仮想アドレス空間の特定のアドレスへの書き込みでデバイスを操作することができるようになる。
一般にストレージデバイスはデバイスファイルではなくファイルシステムを介してアクセスする。ファイルシステムはデータをディスク上のどこに保存したかの管理、空き領域の管理などを行う。
ファイルシステム更新の不整合を防ぐ技術としてジャーナリングとコピーオンライトがある
ジャーナリングは更新に必要なアトミックな処理の一覧を一旦ジャーナル領域に書き出して(ジャーナルログ)から実際に内容を更新する。
コピーオンライトはファイル更新の際に直接同じ位置にデータを書き込むのではなく別の場所にデータを書き込む。
Btrfsではスナップショット機能を使うことができる。
ストレージデバイスの代わりにメモリ上に作成する「tmpfs」というファイルシステムがある。高速にアクセスできるが電源を切るとデータが消える。再起動後に残っている必要の無い/tmp
や/var/run
に使われることが多い。
以下のようにユーザがtmpfsを作ることもできる。
sudo mount -t tmpfs tmpfs /mnt -osize=1G
umountすると消える。
sudo umount /mnt
プロセスの情報を得るための procfs というファイルシステムが存在し、通常は /proc 以下にマウントされる。
プロセスに関するもの以外のカーネルが保持する雑多な情報が procfs に置かれるようになったことへの対策として sysfs が作られた。これは通常 /sys/ 以下にマウントされる。ここから得られる情報の例として /sys/block/ があり、ここにはブロックデバイスごとにディレクトリが存在している。
CPUの動きは単純化すると
- 命令を読み出して命令の内容をもとにメモリからレジスタにデータを読み出す
- レジスタ上のデータを元に計算する
- 計算結果をメモリに書き戻す
メモリアクセスはレジスタアクセスより遅いため、キャッシュメモリが使われる。キャッシュメモリへのデータの読み出しなどはハードウェアレベルで実現されておりカーネルは関与しない
キャッシュメモリの値が更新されてメモリが更新されていない場合、そのキャッシュラインはダーティであると表現する
キャッシメモリがいっぱいの状態でキャッシュ二入っていないデータへのメモリアクセスが頻発するとキャッシュライン内のデータが激しく入れ替わるスラッシングという状態になる
多くのプログラムには時間的局所性と空間的局所性の参照の局所性があり、キャッシュメモリが有効に働く場合が多い
キャッシュメモリは階層化されていることも多く、レジスタに近い方からL1キャッシュ、L2キャッシュ、L3キャッシュと呼ばれる
バッファキャッシュはディスクデータのうちファイルデータ以外のものをキャッシュする仕組み
一度書き込みしたら二度と使わないようなデータの場合はdirect I/Oでキャッシュしないほうが良いこともある。例としてはUSBにバックアップする場合など
スワップはストレージデバイスの一部を一時的にメモリのかわりとして使う仕組み。物理メモリが枯渇した状態でさらにメモリを獲得しようとすると、使用中の物理メモリの一部をスワップ領域と呼ばれるストレージデバイスの領域に退避して空きメモリを作る。
メモリをスワップ領域に書き出すことをページアウトあるいはスワップアウトと呼び、メモリに読み出すことをページインあるいはスワップインと呼ぶ
メモリ不足が一時的なものではない場合、メモリアクセスのたびにページインとページアウトが繰り返されるスラッシングという状態になる
ページキャッシュやバッファキャッシュにおいてディスクとデータをやり取りすることもページイン、ページアウトと呼ぶ