「Linuxのしくみ」を読んだメモ
試して理解 Linuxのしくみ 実験と図解で学ぶOSとハードウェアの基礎知識 第3刷
を読み終えました。自分用に整理したメモを残しておきます。
勉強用リポジトリ: https://github.com/hiroygo/linux-in-practice
調査用のコマンドやファイル
/proc/cpuinfo ファイル
cat /proc/cpuinfo
で CPU 情報を取得できる。
taskset コマンド
プロセスが動作する論理 CPU を指定できる。
$ taskset -c 0,4 ./fuga
time コマンド
プロセスの処理時間を計測できる。
real が経過時間、user がユーザモードの時間、
sys がカーネルがシステムコールを実行していた時間。
$ time ps PID TTY TIME CMD 41058 pts/0 00:00:00 bash 41067 pts/0 00:00:00 ps real 0m0.039s user 0m0.005s sys 0m0.006s
strace コマンド
プロセスのシステムコールを確認できる。
strace の出力は 1 行が 1 つのシステムコールに対応する。
free コマンド
メモリ状況を確認できる。開放可能なカーネルメモリ領域のサイズと free の合計が available になる。 開放可能なカーネルメモリ領域とはバッファキャッシュやページキャッシュなど。 Swap 行がスワップ領域の情報。
$ free total used free shared buff/cache available Mem: 7820180 1660916 3412396 387088 2746868 5450456 Swap: 2097148 0 2097148
ps コマンド
min_flt と maj_flt でページフォルトの総数が取れる。
$ ps -o pid,comm,min_flt,maj_flt PID COMMAND MINFL MAJFL 5617 bash 1524 0 8884 ps 178 0
readelf コマンド
ELF フォーマットの実行ファイルの情報を表示する。以下のサンプルでは、メモリマップ開始アドレスは 0000000000002580
と 000000000000a000
になっている。
$ readelf -S /bin/sleep There are 30 section headers, starting at offset 0x91d8: Section Headers: [Nr] Name Type Address Offset Size EntSize Flags Link Info Align ... [16] .text PROGBITS 0000000000002580 00002580 0000000000003692 0000000000000000 AX 0 0 16 ... [26] .data PROGBITS 000000000000a000 00009000 0000000000000080 0000000000000000 WA 0 0 32 ...
CPU のカーネルモードとユーザモード(第1章, 第2章)
プロセスから直接デバイスやプロセス管理システムなどにアクセスできないようにするため、 CPU にはカーネルモードとユーザモードがある。カーネルモードの時だけ、 デバイスやプロセス管理システムなどにアクセスできる。プロセスがシステムコールを発行すると、 CPU で割り込みというイベントが発生し、CPU はユーザモードからカーネルモードに遷移する。 システムコール処理が終わると CPU はユーザモードに戻る。 デバイスドライバはカーネルモードで動作する。
システムコール(第2章)
システムコールはアーキテクチャ依存のアセンブラコードで呼ぶ必要がある。 (特定のレジスタに実行したいシステムコールの番号を設定するなど) C だとインラインアセンブラという機能がある。これだと手間がかかるので、 OS にはシステムコールを呼び出すラッパー関数が用意されている。 CPU がカーネルモードに遷移すると、システムコールの番号から システムコール・テーブルを参照して、対応するカーネルの処理を呼び出す。
- 参考にさせてもらったサイト
プロセスの状態(第4章)
プロセスの状態には実行中、実行待ち(CPU で実行されるの待ち)、スリープ(イベント待ち)、ゾンビがある。
OOM Killer(第5章)
どうやってもメモリが不足するような場合、Out of Memory(OOM) という状態になる。 この場合、OOM Killer が実行され、適当なプロセスが kill されることがある。
仮想記憶(第5章)
プロセスは仮想記憶というメモリを使う。 仮想記憶のアドレスと物理メモリのアドレスの対応はカーネルメモリ領域のページテーブルで ページという単位で管理される。 仮想記憶を使うことで以下を解決する。
- メモリ断片化
- 物理メモリでは断片化しているメモリ領域を、あたかも連続しているように見せることが出来る。
- 他のプロセスやカーネルメモリ領域へのアクセス制御
- 仮想記憶はプロセスごとに作られ、ページテーブルで管理される。このため他のメモリ領域が見えなくなる。
- 他のプロセスとのアドレス衝突
- プロセスを起動するために、ディスクなどからメモリにプロセスをマッピングする時に、他のプロセスとメモリマップ開始アドレスなどが衝突する可能性がある。仮想記憶はプロセスごとに作られるので回避できる。
- メモリマップ開始アドレスなどは readelf から確認できる。
不正な仮想アドレスにプロセスがアクセスすると、ページフォルトという割り込みが発生し、カーネルのページフォルトハンドラが実行され、
カーネルはプロセスに SIGSEGV
を通知する。
mmap と malloc(第5章)
mmap ではページ単位でメモリを確保する。malloc でバイト単位で確保できるのは、glibc が中間管理してくれているから。
デマンドページング(第5章)
プロセスが mmap でメモリ確保した段階では、実際に物理メモリが割り当てられているわけではない。 確保した仮想アドレス(ページ)に最初にアクセスした時に、ページフォルトが走り、物理メモリが割り当てされる。
コピーオンライト(第5章)
fork で子プロセスを作成した段階では子プロセス用のメモリ領域は確保されていない。ページテーブルだけコピーされる。 この段階では親プロセスと子プロセスはメモリ領域を共有している。 親プロセスまたは子プロセスのどちらかがメモリに書き込むと、対応するページだけページフォルトが走り、 親プロセス用のページと子プロセス用のページに分かれる。
スワップ(第5章)
ストレージにメモリを退避して、空きメモリを確保する仕組み。 スワップイン、スワップアウトが頻繁に繰り返される状態をスラッシングという。
ページキャッシュ(第6章)
ストレージ上のデータをメモリ上にキャッシュする仕組み。プロセスがデータを変更するとページキャッシュも変更され、後でストレージ上のデータも更新される。 メモリが不足してくると、カーネルはページキャッシュを開放する。 ページキャッシュは複数のプロセスからアクセスされる可能性がある。
ファイルシステム(第7章)
ファイルシステムが無いとユーザは自分で、そのデータについて、ストレージデバイス上でのアドレス、サイズを憶えておかないといけない。
ファイルシステムにはデータ本体(ファイル)とメタデータ(データ本体のアドレス、サイズ、名前、作成日時など)がある。
tmpfs はメモリ上のファイルシステムでアクセスが高速、再起動で消去されるというもの。/tmp
などに使われる。
ジャーナリング(第7章)
ファイルシステムの不整合を防ぐ仕組み。ファイルシステムのジャーナル領域にアトミックで実行されるべき複数のファイルシステム操作を保存してから、操作を実行する。
キャラクタデバイスとブロックデバイス(第7章)
- キャラクタデバイス: キーボード、マウスなど。シークできない
- 参考にさせてもらったサイト: https://qiita.com/koara-local/items/6484723d29afad4c3afb
- ブロックデバイス: HDDなど