Open40

試して理解 Linuxのしくみ

ktoyodktoyod

絶対に死なないプロセスはuninterruptible sleepという状態になっていてps auxのSTATの一文字目がDになる

ktoyodktoyod

ゾンビプロセス: 終了したけど親プロセスが終了状態を得ていないプロセス
孤児プロセス: 親がwait()系システムコールの実行前に終了したプロセス

ktoyodktoyod

Goのプログラムは基本的にライブラリをすべて静的リンクするので共有ライブラリに依存しない

ktoyodktoyod

ps ajxでセッションIDやプロセスグループのPGIDが確認できる

ktoyodktoyod

ページテーブルはカーネルによって作られるが、プロセスが仮想アドレスにアクセスした際に物理アドレスに変換するのはCPU

ktoyodktoyod

トランスペアレントヒュージページによってページテーブルのためのメモリ使用量を自動で抑えることができる

ktoyodktoyod

mmapシステムコールによってプロセスにメモリ領域を割り当てても即時に物理メモリが割り当てられるわけではなく、プロセスがアクセスした際に初めて物理メモリが割り当てられる。これをデマンドページングという。

ktoyodktoyod

fork()関数を発行した場合、子プロセスには親プロセスのページテーブルのみがコピーされ物理メモリは共有される、かつ親子ともに読み込み専用となる。どちらかのプロセスが書き込みを行おうとした際に初めて物理メモリが新規に割り当てられ内容もコピーされる、かつ書き込み可能となる。これをコピーオンライト(CoW)と呼ぶ。

ktoyodktoyod

このあたりは実際にメモリアクセスした際に発生したページフォールトをカーネルのページフォールトハンドラが処理することで実現している

ktoyodktoyod

ddコマンドにSIGUSR1を送ると進捗状況を表示してくれる

ktoyodktoyod

プロセス作成、スレッド作成ともにclone()システムコールが呼ばれるが、前者では仮想アドレス空間を共有せず、後者では共有する

ktoyodktoyod

マルチスレッドはプロセス内に複数の流れを作る

ktoyodktoyod

スレッドの実現方法はカーネルスレッドとユーザスレッドがあり、goroutineは後者。前者はプロセススケジューリング上で各スレッドがプロセスと同様の扱いを受けるが、後者はカーネルがスレッドを認識できないのでプロセスごとにスケジューリングされCPUが回ってきたときに各スレッドにCPUリソースを割り当てるかはスレッドライブラリの責任となる。

ktoyodktoyod

プロセスがデバイスファイルを操作するとカーネルの中のデバイスドライバがデバイスにアクセスする。プロセスは通常のファイルと同じようにシステムコールで操作する。

ktoyodktoyod

キャラクタデバイス: 読み出しと書き込みはできるがシーク操作はできない。端末やキーボード、マウスなど。
ブロックデバイス: 読み書き以外にもシークができる。HDDやSSDなど。

ktoyodktoyod

デバイスを直接操作する場合デバイスのレジスタにアクセスする。どのレジスタにアクセスするとどのような操作をするのかはデバイスによる。CPUのレジスタとは名前は同じだが別物

ktoyodktoyod

メモリマップトI/Oはカーネルの仮想アドレス空間に物理メモリだけでなくデバイスのレジスタもマップする。これによって仮想アドレス空間の特定のアドレスへの書き込みでデバイスを操作することができるようになる。

ktoyodktoyod

一般にストレージデバイスはデバイスファイルではなくファイルシステムを介してアクセスする。ファイルシステムはデータをディスク上のどこに保存したかの管理、空き領域の管理などを行う。

ktoyodktoyod

ファイルシステム更新の不整合を防ぐ技術としてジャーナリングとコピーオンライトがある

ktoyodktoyod

ジャーナリングは更新に必要なアトミックな処理の一覧を一旦ジャーナル領域に書き出して(ジャーナルログ)から実際に内容を更新する。

ktoyodktoyod

コピーオンライトはファイル更新の際に直接同じ位置にデータを書き込むのではなく別の場所にデータを書き込む。

ktoyodktoyod

ストレージデバイスの代わりにメモリ上に作成する「tmpfs」というファイルシステムがある。高速にアクセスできるが電源を切るとデータが消える。再起動後に残っている必要の無い/tmp/var/runに使われることが多い。

ktoyodktoyod

以下のようにユーザがtmpfsを作ることもできる。

sudo mount -t tmpfs tmpfs /mnt -osize=1G

umountすると消える。

sudo umount /mnt
ktoyodktoyod

プロセスの情報を得るための procfs というファイルシステムが存在し、通常は /proc 以下にマウントされる。

ktoyodktoyod

プロセスに関するもの以外のカーネルが保持する雑多な情報が procfs に置かれるようになったことへの対策として sysfs が作られた。これは通常 /sys/ 以下にマウントされる。ここから得られる情報の例として /sys/block/ があり、ここにはブロックデバイスごとにディレクトリが存在している。

ktoyodktoyod

CPUの動きは単純化すると

  1. 命令を読み出して命令の内容をもとにメモリからレジスタにデータを読み出す
  2. レジスタ上のデータを元に計算する
  3. 計算結果をメモリに書き戻す
ktoyodktoyod

メモリアクセスはレジスタアクセスより遅いため、キャッシュメモリが使われる。キャッシュメモリへのデータの読み出しなどはハードウェアレベルで実現されておりカーネルは関与しない

ktoyodktoyod

キャッシュメモリの値が更新されてメモリが更新されていない場合、そのキャッシュラインはダーティであると表現する

ktoyodktoyod

キャッシメモリがいっぱいの状態でキャッシュ二入っていないデータへのメモリアクセスが頻発するとキャッシュライン内のデータが激しく入れ替わるスラッシングという状態になる

ktoyodktoyod

多くのプログラムには時間的局所性と空間的局所性の参照の局所性があり、キャッシュメモリが有効に働く場合が多い

ktoyodktoyod

キャッシュメモリは階層化されていることも多く、レジスタに近い方からL1キャッシュ、L2キャッシュ、L3キャッシュと呼ばれる

ktoyodktoyod

バッファキャッシュはディスクデータのうちファイルデータ以外のものをキャッシュする仕組み

ktoyodktoyod

一度書き込みしたら二度と使わないようなデータの場合はdirect I/Oでキャッシュしないほうが良いこともある。例としてはUSBにバックアップする場合など

ktoyodktoyod

スワップはストレージデバイスの一部を一時的にメモリのかわりとして使う仕組み。物理メモリが枯渇した状態でさらにメモリを獲得しようとすると、使用中の物理メモリの一部をスワップ領域と呼ばれるストレージデバイスの領域に退避して空きメモリを作る。

ktoyodktoyod

メモリをスワップ領域に書き出すことをページアウトあるいはスワップアウトと呼び、メモリに読み出すことをページインあるいはスワップインと呼ぶ

ktoyodktoyod

メモリ不足が一時的なものではない場合、メモリアクセスのたびにページインとページアウトが繰り返されるスラッシングという状態になる

ktoyodktoyod

ページキャッシュやバッファキャッシュにおいてディスクとデータをやり取りすることもページイン、ページアウトと呼ぶ