本記事は全5回に渡る Linux カーネルの解説のうち第3回「メモリ管理」に関する記事です。
その他の Linux カーネルの解説については以下の記事をご覧ください。
- 【Linux カーネル: OS 基礎入門1】OS、カーネルとは
- 【Linux カーネル: OS 基礎入門2】プロセス管理・CPU 割り当て
- 【Linux カーネル: OS 基礎入門3】メモリ管理 ←イマココ
- 【Linux カーネル: OS 基礎入門4】ファイルシステム
- 【Linux カーネル: OS 基礎入門5】メモリ管理
メモリとは
メモリとは、CPU が直接読み書きできるものです。実行中のプロセスを置いたり、データを置いたりするために利用します。
なお、本記事で記載する「メモリ」は「メインメモリ」を表します。
その他のメモリの種類については以下に記載します。
メモリの種類
メモリには以下の3種類があります。
- キャッシュメモリ
- メインメモリ(主記憶装置/Primary Memory)
- ストレージ(補助記憶装置/Secondary Memory)
レジスタを含めたそれぞれのメモリの比較は以下のとおりです。

キャッシュメモリ
キャッシュメモリは、「CPU」と「メインメモリ」間のバッファとして機能するメモリです。

「図1:レジスタとメモリの比較」に記載のとおり、高速アクセス、低用量であることから、CPU が頻繁にアクセスするメインメモリのデータをキャッシュメモリにキャッシュします。
メインメモリ(揮発性メモリ/主記憶装置/Primary Memory)
メインメモリは、CPU が実行中のプログラム(プロセス)を置くために利用します。

メインメモリは以下の特徴を持ちます。
- 揮発性(電源を切るとデータが消える)
- キャッシュメモリより遅く、ストレージより早い
- メインメモリ無しでコンピュータを実行することは出来ない
- CPU は実行中のプロセスやデータをメインメモリに置くため
ストレージ(不揮発性メモリ/補助記憶装置/Secondary Memory)
ストレージはデータを永続的に保存する(電源を切っても消えない)ために利用します。

CPU はストレージに直接アクセスしません。CPU がストレージのデータにアクセスする場合は、以下の手順となります。
- データをストレージからメインメモリに転送
- CPU はメインメモリ上のデータにアクセス
ストレージの特徴は以下のとおりです。
- 不揮発性(電源を切ってもデータが消えない)
- メインメモリより遅い
- ストレージ無しでコンピュータを実行することも可能
メモリ使用率や内訳を確認 free
free コマンドを利用することで、メインメモリ使用率、および内訳を確認することができます。
total used free shared buff/cache available Mem: 8063684 358512 7180624 652 524548 7473952

- total: システムに搭載されているメモリ
- used: カーネルや各プロセスが利用しているメモリの総量。
- free: 見かけ上の空き容量
- buff/cache: カーネル内にあるバッファキャッシュとページキャッシュの総量
- 上述したキャッシュメモリとは別物
- メインメモリ内のキャッシュ
- available: free + カーネル内メモリ領域の開放可能なメモリ
メモリを使用してみる
今回は /dev/shm にマウントされた共有メモリを利用します。
ファイルシス タイプ サイズ 使用 残り 使用% マウント位置
devtmpfs devtmpfs 3.9G 0 3.9G 0% /dev
tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
tmpfs tmpfs 3.9G 420K 3.9G 1% /run
tmpfs tmpfs 3.9G 0 3.9G 0% /sys/fs/cgroup
/dev/nvme0n1p1 xfs 64G 20G 45G 30% /
tmpfs tmpfs 788M 0 788M 0% /run/user/1000
メモリを2GiB 利用してみます。
total used free shared buff/cache available Mem: 8063684 358512 7180624 652 524548 7473952
2048+0 レコード入力 2048+0 レコード出力 2147483648 バイト (2.1 GB) コピーされました、 0.899953 秒、 2.4 GB/秒
total used free shared buff/cache available Mem: 8063684 362620 5043644 2097804 2657420 5370028
free と Available が 2GiB 減少し、shared, buff/cache が 2GiB 増加したことがわかります。
メモリが揮発性であることを確認
再起動し、メモリの内容が消えることを確認します。
tmpfs tmpfs 3.9G 2.0G 1.9G 53% /dev/shm
tmpfs tmpfs 3.9G 0 3.9G 0% /dev/shm
メモリ管理とは
メモリ管理とは、メインメモリにプロセスを割り当てたり、メモリから溢れたプロセスをストレージに移動したりするカーネルの機能ことです。
Linux カーネルは主に次の方法でメモリを管理します。
- スワッピング
- コンパクション for フラグメンテーション
- バーチャルメモリ(仮想記憶)
スワッピング
スワッピングは、メインメモリから溢れたプロセスをストレージに移動したり、ストレージに存在するプロセスを CPU で処理するためにメインメモリに移動することです。
スワッピングはプロセスの移動先によって以下のように呼ばれます。
- スワップイン:プロセスが「ストレージ-->メインメモリ」に移動
- スワップアウト:プロセスが「メインメモリ-->ストレージ」に移動
なお、ストレージへのアクセスは CPU の動作と比較してとんでもなく遅いので、スワッピングが発生するとコンピュータの性能は低下します。
Out Of Memory(メモリ不足)
Out Of Memory は、「メインメモリ・ストレージのスワップ領域」が埋まっている状況で、メモリを確保すると発生するエラーです。
システムは開放可能なメモリを解放することで Out Of Memory を回避します。
OOM Killer
OOM Killer は、Linux カーネルが適当なプロセスを選択して kill(強制終了)します。
Out Of Memory が発生した際に開放可能なメモリが無く、システムが稼働するために必要なメモリが確保できない場合は OOM Killer が発生します。
コンパクション for フラグメンテーション
フラグメンテーションは、メインメモリの空き容量がバラバラに存在することを言います。(連続していない領域に複数の空き容量がある)
コンパクションは、フラグメンテーションが発生した空き容量を1つにまとめることです。(連続した領域に空き容量を確保することです。)

https://www.tutorialspoint.com/operating_system/os_memory_management.htm
フラグメンテーションが発生する原因
フラグメンテーションは、プロセスによって「処理の時間・スワップアウトの優先度」が異なるため発生します。
メモリの空き容量は、プロセスの「処理が完了・スワップアウト」により発生しますが、このタイミングがプロセスによって異なるため連続していない領域に空き容量が発生します。
コンパクションを実施する理由
コンパクションを実施する主な理由は、メモリへのアクセス速度が向上することです。
これは空き容量が1つの領域にまとめられるため、空き容量の開始位置を探すのが1回で済むためです。
バーチャルメモリ(仮想記憶)
バーチャルメモリとは、プロセスから見たメモリのことです。
実際のデータは、メインメモリ + ストレージのスワップ領域に保存されます。

なお、仮想アドレス(Virtual Adress)と対比して、メインメモリのアドレス空間を物理アドレス(Physical Adress)と呼びます。
バーチャルメモリが必要な理由は以下の3つです。
- メインメモリより大きなサイズのプロセスを起動可能
- メインメモリを保護可能(別プロセスからの上書きを避ける)
- マルチプロセスの実装が容易
メインメモリより大きなサイズのプロセスを起動可能
- プロセスをメインメモリへマッピング
- 溢れた容量はストレージにマッピング
- CPU がストレージにあるデータを処理する場合はスワッピング

メインメモリを保護可能(別プロセスからの上書きを避ける)
- 他のプロセスが存在する物理アドレスにはマッピングを避ける
- カーネル用の物理アドレスにマッピングを避ける

マルチプロセスの実装が容易
- 各プロセスが固有の仮想アドレスを持つ
- そのため、他のプロセスのアドレス使用状況を気にしなくて良い
- 物理アドレスには、プロセスの上書きを避けてマッピングするだけ
- 物理アドレス上で連続していなくても、連続したメモリ(配列等)を確保可能

バーチャルメモリの実装
バーチャルメモリは次の2つの方式で実装されます。
- ページング方式
- セグメント方式
なお、CPU がバーチャルメモリを利用してメインメモリにアクセスする場合は、MMU(Memory Management Unit)と呼ばれるハードウェアが仮想アドレスから物理アドレスへの変換します。
ページング方式
ページング方式は、プロセスの仮想アドレス空間を"ページ"と呼ばれる固定サイズのブロックに分割するメモリ管理手法です。
各ページがメインメモリのどの物理アドレスにマッピングされているか記録したものをページテーブルと呼びます。
なお、ページサイズは getconf PAGESIZE コマンドで確認可能です。
4096
以降の例ではわかりやすいようにページサイズは 100Bytes で説明します。

ちなみに、CPU が仮想アドレス 200-300 にアクセスした場合、ページフォールトが発生しストレージからメインメモリに対象データがスワップインされます。
また、カーネル領域や既に別プロセスが稼働する物理アドレスにマッピングした場合はセグメンテーションフォールトが発生します。
セグメント方式
セグメント方式とは、プロセスの仮想アドレス空間を"セグメント"と呼ばれる可変サイズのブロックに分割するメモリ管理手法です。
セグメントとは、あるルールによってグループ分けされるデータのことです。

各セグメントは異なるサイズであることがわかります。
なお、プロセスの各セグメントの意味は以下の記事をご覧ください。
なお、各セグメントがページで分割されている方式をページ化セグメンテーションといいます。
ページ置換アルゴリズム
ページ置換アルゴリズムとは、ページフォールト(メインメモリにデータが無いこと)が発生した際に、どのページをストレージのデータと置換(スワッピング)するか決める方法のことです。
ページフォールトが増加するとスワッピングが発生すると処理が遅くなります。
そのため、ページフォールトの発生が低いページ置換アルゴリズムは良いアルゴリズムと言えます。
代表的なページ置換アルゴリズム2つを紹介します。
- First In First Out (FIFO) algorithm
- Least Recently Used (LRU) algorithm
その他のアルゴリズムについては wiki にまとまっているのでご覧ください。
First In First Out (FIFO) algorithm
一番古いページを置き換えるアルゴリズムです。

Least Recently Used (LRU) algorithm
最も長く使用していないページが置換されます。
FIFO と異なり、古いページでも最近利用されている場合は置換されません。

最後に
Linux カーネル「メモリ管理」に関する説明は以上となります。
その他の Linux カーネルの機能について知りたい場合は以下の記事をどうぞ。
- 【Linux カーネル: OS 基礎入門1】OS、カーネルとは
- 【Linux カーネル: OS 基礎入門2】プロセス管理・CPU 割り当て
- 【Linux カーネル: OS 基礎入門3】メモリ管理 ←イマココ
- 【Linux カーネル: OS 基礎入門4】ファイルシステム
- 【Linux カーネル: OS 基礎入門5】メモリ管理
参考書籍
以下の書籍を参考にしました。
参考サイト
以下のサイトを参考にしました。
コメント