読書記録:[試して理解]Linuxのしくみ~実験と図解で学ぶOSとハードウェアの基礎知識

こちらを読んだ記録。
gihyo.jp

1章 コンピュータシステムの概要

カーネル
カーネルモードで動作する、OSの核となる処理をまとめたプログラム
CPUやメモリなどのリソースを管理

2章 ユーザモードで実現する機能

プロセス(CPU:ユーザモード)…カーネルに対して処理を依頼するシステムコールを発行
デバイスドライバ(カーネルモード)
→ デバイス(カーネルモード)

システムコールはOSの提供するラッパー関数を呼び出すだけで良い。
Linuxではシステムコールのラッパー関数を含む、標準Cライブラリ(通常はglibc)が提供されている。

3章 プロセス管理

・プロセス生成の関数
fork()関数:同じプログラムの処理を複数のプロセスに分けて処理する(親プロセスのメモリを子プロセス用にコピーして親子で処理を分岐する)。
execve()関数:全く別のプロセスを生成する(あるプロセスを別のプロセスで置き換える)

・終了処理
exit()を呼び出してプロセスに割り当てていたメモリを全て回収する。

4章 プロセススケジューラ

プロセススケジューラ:複数のプロセスを同時に動作させる機能。
1つのCPU上で同時に処理するプロセスは1つだけ。
複数プロセスが実行可能な場合、個々のプロセスを適当な長さの時間ごとにCPU上で順番に処理する。

コンテキストスイッチ:論理CPU上でプロセスが切り替わること

・プロセスの状態
主に 実行状態/実行待ち状態/スリープ状態/ゾンビ状態
ストレージデバイスのアクセス待ち状態が長期間起こっている場合は何かしら問題あり。

スループット:単位時間あたりの総仕事量。高いほど良い。
レイテンシ:それぞれの処理の開始から終了までの経過時間。短いほど良い。

・論理CPUが常に動いている(アイドル状態がない)かつ実行待ちのプロセスがない場合にスループットもレイテンシも最大になる。
→実際は状態変化し続けている。
 アイドル状態(スループット低) ⇆ プロセス実行中(待ちなし) ⇆ プロセス実行中(待ちあり、レイテンシ長)

・論理CPUが複数ある場合はロードバランサかグローバルスケジューラにより、プロセスは公平に分配される。プロセスに実行優先度をつけると、通常より多くにCPU時間が与えられる。

5章 メモリ管理

カーネルのメモリ管理システムによって全メモリが管理されている。
Out of Memory:空きメモリが少なくなるとカーネル内の解放可能なメモリ領域が解放されるが、その後もメモリ使用量が増え続けメモリ不足で何もできなくなった状態

仮想記憶

<基本的な仕組み>
・プロセスからメモリに直接アクセスせず、仮想アドレスを用いて間接的にアクセスする。ページテーブルを使用して仮想アドレスから物理アドレスに変換、ページテーブルエントリ(1つのページに対応するデータ)に仮想アドレスと物理アドレスの対応情報が入っている。
・物理メモリ上では断片化している領域を仮想アドレス空間上で1つの領域として使うことができる。
・プロセスごとに仮想アドレス空間が作られるため、他のプロセスのメモリにはアクセスできない。

<これを応用した仕組み>

ファイルマップ ファイルの領域を仮想アドレス空間上にメモリマップする
デマンドページング 仮想アドレスに対応する物理アドレスは該当ページに最初にアクセスした時に割り当てる
コピーオンライト はじめは親プロセスと子プロセスで仮想アドレスはそれぞれ持つがメモリは共有で持つ、書き込みが起こった際にアクセスされたページを別のメモリにコピーして書き込む
スワップ 物理メモリがOOMの場合、既存の使用中の物理メモリの一部をストレージデバイスに退避して空きメモリを作り出す
階層型ページテーブル ページテーブルを階層構造で持つ
ヒュージページ 大きいサイズのページを使用し、ページテーブルに必要なメモリ量を減らす

6章 記憶階層

・記憶装置の階層構造
レジスタキャッシュメモリ→メモリ→ストレージデバイス
メモリからデータを読み出し、レジスタで計算(処理速い)、結果をメモリに書き戻す

キャッシュメモリ

・メモリからまずキャッシュメモリに書き出すことで高速化される(物理メモリへのアクセスの高速化)。
・データを書き換えた場合は、ダーティという印が付けられ、所定のタイミングでバックグラウンド処理としてメモリに書き戻される。
・階層型キャッシュメモリ:「L1」「L2」などの名前がついており、どのレベルのキャッシュを持つかはCPUに依存する。L1キャッシュが最もレジスタに近く、容量が少なく高速。
キャッシュメモリによる高速化は、プログラムが参照の局所性(ある時点でアクセスされたデータは再度アクセスされる可能性が高い、それに近い場所のデータにアクセスする可能性が高い)を持つため効果的に働く。


Translation Lookaside Buffer(TLB):ページテーブルを参照して仮想アドレスを物理アドレスに変換することを高速化する領域。

ページキャッシュ:ストレージデバイス上のファイルデータをメモリにキャッシュして、ストレージデバイスへのアクセス速度の遅さを埋める。
バッファキャッシュファイルシステムを使わずに、デバイスファイルを用いてストレージデバイスに直接アクセスする際に使う領域。
→この2つまとめて、ストレージ内のデータをメモリ上に置いておく仕組み

ハイパースレッド
CPUコア中の一部の資源を複数用意することでハイパースレッドとして分割して、メモリアクセスのレイテンシが長いためにCPU上で発生しているデータ転送待ち時間を有効活用する機能。
ただしプロセスの挙動によってはスループットが劣化することもあり、20-30%向上すれば良い方。

7章 ファイルシステム

ストレージデバイス内のデータにはファイルシステムを介してアクセスする。
Linuxは、etx4 / XFS / Btrfs など複数のファイルシステムを扱える。

クォータ:用途ごとに使用できるファイルシステムの容量を制限する機能。

・強制電源断が起こるとファイルシステムの不整合が起こる恐れがあるため、以下の方式により不整合を防ぐ。
ジャーナリング:ジャーナル領域に処理の一覧を書き出しておく。
コピーオンライト:更新するデータを別の場所に全て書き込んでから前のデータを破棄する。
fsckコマンドで整合性のある状態への復帰もできるが、時間がかかる上に失敗することもある、望んだ状態に復元されずデータが削除されることがあるため推奨できない。

・デバイスファイル
キャラクタデバイス(端末、キーボード、マウスなど)
ブロックデバイス(HDD, SSDなどのストレージデバイス)

・様々なファイルシステム
メモリベース(tmpfs):ストレージデバイスの代わりにメモリ上にファイルを作成する
ネットワークファイルシステムリモートホスト上のファイルにアクセスする
仮想ファイルシステム(procfs, sysfs, cgroupfs):カーネル内の情報を得る、カーネルの挙動を変更する

・Btrfsはetx4 / XFS より豊富な機能を持つ
マルチボリューム / スナップショット / RAID(データを複数のHDDに分散して保存する) / データ破損検知・修復

8章 ストレージデバイス

・HDD:データを磁気情報で表現して、プラッタという磁気ディスクに記憶するストレージデバイス。セクタという単位で読み書きする。
アクセス要求 → スイングアームの移動、プラッタの回転(ここが時間かかる) → データ転送
データの配置やアクセスするサイズを工夫して、機械的動作の部分が短くなるようにする。
SSD機械的動作がなくデータ検索をすることができ、HDDより高速。

・ブロックデバイス
ブロックデバイス(HDDやSSDなどの、ランダムアクセス可能かつ一定量の大きさ(セクタ)ごとにアクセス可能なデバイス)は共通の処理が多いため、カーネル内のブロックデバイス層が担当する。

I/Oスケジューラ ブロックデバイスのアクセス要求を一定期間貯めておき、マージ・ソートしてからI/O要求することで性能を向上させる。ただし、SSDの場合データ検索に時間がかからないため、I/O要求を貯める処理時間のせいで逆に性能劣化することもある。
先読み データのアクセスに空間的局所性があることを利用して、アクセスされたストレージデバイス内の領域に続く領域を事前に読み込む。