【OS/Linux】プロセス、スレッド、メモリ管理について

## 知識不足だー
SRE業務についてから、OSの仕組みやLinuxの仕組みの知識が不足していると日々感じます。
最近はその周辺の本を読み漁り、知識を徐々に補完していってなんとかやってます。
この記事はその補完した際のアウトプットになります。
ご指摘ありましたら、コメントいただけると幸いです。

またこの記事を書くにあたり、下記の書籍を主に参考にしました！
[インフラエンジニアの教科書2 スキルアップに効く技術と知識](https://www.amazon.co.jp/dp/B01KSUGP28/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)

## プロセスとスレッド
### プロセス
OS上の最小実行単位のことを指します。
プロセスは、CPUリソースが割り当てられる事によって、実行されます。

#### プロセスを構成する要素
- PID
- プログラム
- データ
- ファイル記述子
- コンテキスト
- スレッド

#### 状態遷移
「実行まち」、「実行中」、「休止中」の状態があります。
プロセスが作成されてからその都度、様々な状態に遷移します。

#### 新しいプロセスの作成
新しいプロセスを作成する場合は、すでに存在しているプロセスをコピーする(forkすると言います)ことから始まります。
コマンドでも確認できるので、ぜひ確認してみてください。
[pstree](https://www.atmarkit.co.jp/ait/articles/1603/29/news024.html)

仮にlsコマンドを打ち込んだ場合は下記の順序で実行されます。

```
1. lsコマンドを打つ
2. bashプロセスがforkされる
3. 子プロセス生成(仮想メモリを割り当てられる。)
4. execシステムコールによって子プロセスの中身がlsコマンドになる
```

### スレッド
並列処理ができるように、プロセス内に複数作ることができるタスクの実行単位のことです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148392/449ccc4e-045d-7415-e440-64ea63bc5266.png)


#### プロセスとの違い
>同じ構造体なのですが、buildするときにメモリ空間をコピーするかなどのフラグを渡すことで、threadを実現しています。

>Processを作るときには、親プロセスのすべての情報が子プロセスに引き継がれ、さらに子プロセス用に仮想メモリを確保されるので、比較的重い処理になります。

下記記事でも書かれている通り、歴史的背景でいうと、初めはプロセスだけで、スレッドはなかったです。
そしてプロセスを作成するときは、親のプロセスが子プロセスをforkして全ての情報が引き継がれので、どうしても非効率になってしまう。
それをプロセスのメモリ空間を共有し、並列処理を実現することができているのが**スレッド**だと考えています。

[並行処理、並列処理のあれこれ - Qiita](https://qiita.com/Kohei909Otsuka/items/26be74de803d195b37bd#%E4%B8%A6%E5%88%97%E5%87%A6%E7%90%86%E3%81%A7%E3%81%A9%E3%81%86%E3%81%84%E3%81%86%E3%81%A8%E3%81%8D%E3%81%AB%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E3%81%8C%E3%81%82%E3%81%8C%E3%82%8B%E3%81%AE%E3%81%8B%E7%90%86%E8%AB%96)

#### ミュータックス
1つのスレッドからしか書き換えができないようにしている仕組み

## メモリ管理
プロセスを作成するときは、仮想メモリを割り当てられ、プロセスが実行されます。

### 全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148392/ebc643bc-a962-72f1-bb21-539d71b178f7.png)

### 物理メモリ
主記憶装置（メインメモリ/RAM）を指します。

### 仮想メモリ
システムに実際以上のメモリがあるかのように見せる仕組みのことを指します。
プロセスがメモリアクセスを行う際は、仮想メモリを通して行います。

[The Linux Kernel](http://archive.linux.or.jp/JF/JFdocs/The-Linux-Kernel-4.html)

### MMU
仮想記憶のアドレスと物理メモリのアドレスの変換は CPUに組み込まれたMMU (Memory Management Unit: メモリ管理ユニット) が行う。MMUは**ページングテーブル**という情報を持って入り、それを使用し、変換を行なっています。
またこの対応付のことをマッピングと呼びます。
[【図解】仮想記憶(仮想メモリ)の本質や仕組み、メリット　〜スワップ、MMU、ページングテーブルについて〜 \| SEの道標](https://milestone-of-se.nesuke.com/sv-basic/architecture/virtual-memory-and-swap/)

### スワップ
プロセスがOSに対して、メモリ割り当てを要求した時に物理メモリが不足していたとします。
その場合、すでに割り当てられている物理メモリ空間をスワップ領域に逃します。(スワップアウト)
逆に、追い出したデータが必要になったときは、スワップ領域から物理メモリ空間にデータが戻ってきます。(スワップイン)
仮想記憶のうち、HDDを使用する使用する領域がスワップ領域ということです。

### システムコール
>OSは『システムコール』という関数(API)を一般的なプログラム向けに提供しており、原則そのシステムコールにより間接的にアクセスすることになっています

インターフェースのイメージだと思っています。・
Linuxカーネルへのアクセスを仲介してくれます。

[【図解】初心者向けユーザー空間とカーネル空間,システムコール,MMU/メモリ保護,の仕組み \| SEの道標](https://milestone-of-se.nesuke.com/sv-basic/architecture/user-space-kernel-space/)

### Linuxカーネル
>ハードウェアとソフトウェアの仲立ちをしてくれるものがOSです。LinuxカーネルはそんなOSの基幹部分の機能である

下記記事のこの説明がかなりしっくりきました。

[【初心者向け】Linuxカーネルって一体なんだ？ - Qiita](https://qiita.com/uguis410/items/17ec1e447e9716bfdca7)

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148392/28c2b0ba-3e27-73dd-7b80-32da0f853e4f.png)
下記より引用
[ファイル:Layer-of-System.png](https://uc2.h2np.net/index.php/%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB:Layer-of-System.png)

### カーネル空間とユーザー空間
>ユーザー空間とは、アプリケーション（OS上で動作するソフトウェア）が使用するメモリ領域のことであり、
>カーネル空間とは、カーネルが使用するメモリ領域のことを指します

これはMMUの中で、カーネル空間とユーザー空間が分けられています。

#### なぜ分ける必要があるのか
カーネル空間に誰でもアクセスできるようになった場合、OSに対してアクセスできることに繋がります。
これは、同時にOSそのものを破壊しかねません。
そのため、あえてこのように空間を分けることにしているのです。

#### カーネル空間を使用したい場合
ユーザーモードのプロセスでは、カーネル空間にアクセスすることはできません。
だけど使用したいというときにそこで、**Context Switch**という機能によってユーザモードとカーネルモードの切り替えを実現することができています。

[Linuxカーネル超入門](https://www.slideshare.net/masutaka/linux-4084509)
[ユーザー空間とカーネル空間 \| Linuxデバイスドライバ開発入門](http://linux-dvr.biz/archives/39)