本記事は Linux カーネルの解説のうち第3回「メモリ管理」に関する記事です。
なお、本記事は以下の書籍を参考にしています。
その他の Linux カーネルの解説については以下の記事をご覧ください。
- 【Linux カーネル: OS 入門1】OS、カーネルとは
- 【Linux カーネル: OS 入門2】CPU・プロセス管理
- 【Linux カーネル: OS 入門3】メモリ管理 ←イマココ
- 【Linux カーネル: OS 入門4】ストレージ管理・ファイルシステム
- 【Linux カーネル: OS 入門5】ファイルシステムの機能一覧
- 【Linux カーネル: OS 入門6】I/O デバイス管理
メモリとは
メモリとは、CPU が直接読み書きできる記録デバイスです。
メモリは、プロセス(実行中のプログラム)を置くために使います。

プロセスについては以下の記事で解説していますので、詳細を知りたい方はご覧ください。
メモリ使用率の確認コマンド
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
メモリ管理とは
メモリ管理とは、以下のカーネルの機能のことです。
・プロセスにメモリを割り当てる方法 (仮想メモリ)
・不要なプロセスをメモリから開放 (ページング、スワップ、OOM Killer)
カーネルについては以下の記事で解説していますので、詳細を知りたい方はご覧ください。
メモリ管理をする上での問題点
メモリでプロセスを管理する上で問題となることは、主に以下の4つです。
プロセスサイズの制約
プロセスサイズがメモリサイズより大きくなる場合、メモリ不足によりプログラムは起動できません。

フラグメンテーション
フラグメンテーションは、メインメモリの空き容量がバラバラに存在することを言います。(連続していない領域に複数の空き容量がある)

フラグメンテーションの問題は、メモリの空き容量の合計がプロセスサイズよりも大きいのに、プロセスにメモリを割り当てられないことです。

しかし連続した空き容量は 100 Bytes しか無いのでプロセスにメモリが割り当てられない
これを解決するために、コンパクションと呼ばれるフラグメンテーションが発生した空き容量を1つにまとめる処理を行います。(連続した領域に空き容量を確保します。)

他プロセスのメモリ領域を破壊
プロセスが利用するアドレスに既に他のプロセス等が存在する場合、上書きにより元のプロセスを破壊してしまいます。

自プロセス内のメモリ領域を破壊
「プログラムのメモリアドレスの指定ミス」や「悪意のある攻撃」等により自身のプロセスを上書きし、破壊してしまう

今まで紹介した以下の4つを解決するために、仮想メモリという仕組みを利用します。
仮想メモリ (Virtual Memory)
仮想メモリとは、プロセスから見たメモリのことです。
仮想メモリの実態は、「物理メモリ」 + 「ストレージのスワップ領域」に記憶されてます。

・CPU が「仮想アドレス」から「物理アドレス」にアクセスする場合は、MMU(Memory Management Unit)と呼ばれるハードウェアが変換します。
https://www.tutorialspoint.com/operating_system/os_virtual_memory.htm
仮想メモリは次の3つの方式で実装されます。
- ページング方式
- セグメント方式
- ページ化セグメンテーション方式
ページング方式
ページング方式は、「ページ (固定のサイズ) 」でメモリを分割する方式です。
また、仮想メモリと物理メモリのアドレスの対応を記録したものをページテーブルと言います。

これにより、上述の物理メモリ上でプロセスを管理する際に発生する問題のうち、以下の3つを解決できます。
- プロセスサイズの制約 (物理メモリに乗り切らない分は、ストレージに置いておく)
- フラグメンテーション (仮想メモリ上では連続している。物理メモリにはページ単位でマッピング可能)
- 他プロセスのメモリ領域の破壊 (別のプロセスが利用中の物理アドレスに対するマッピングを禁止)
ページサイズの確認
ページサイズは getconf PAGESIZE コマンドで確認可能です。
4096
ページフォールト/ページング
ページフォールトは、物理メモリ上にページが見つからない状態を表します。

例えば、CPU が仮想アドレス 300-400 にアクセスするとページフォールトが発生します。
カーネルはページフォールトを検出するとページングと呼ばれる以下の2つの処理を行います。
なお、ページアウトするページは、ページ置換アルゴリズムによって選択されます。
ページフォールトが増加し、ページングが頻発するとストレージへのアクセスが頻発するため、処理が遅くなります。そのため、ページフォールトの発生が低いページ置換アルゴリズムは良いアルゴリズムと言えます。
代表的なページ置換アルゴリズム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 と異なり、古いページでも最近利用されている場合は置換されません。

セグメント方式
セグメント方式は、「セグメント (データ分類ごと)」でメモリを分割する方式です。
プロセスは次の5つのセグメントを持ちます。

- テキスト・セグメント: CPU が実行する機械語命令
- データ・セグメント: 初期化済みの static 変数 or グローバル変数
- bss・セグメント: 初期化していない static 変数 or グローバル変数
- ヒープ・セグメント: プロセス実行時に動的に確保される領域 (malloc 等)
- スタック・セグメント: スコープが終了すると消えるデータ (ローカル変数、関数パラメータ、メソッド等)

これにより、上述の物理メモリ上でプロセスを管理する上で発生する問題のうち、以下の1つを解決できます。
- 自プロセス内のメモリ領域の破壊 (別のセグメントに書き込み禁止 = セグメンテーションフォールト)
スワップ
スワップは、物理メモリが埋まっており、新規プロセスが物理メモリに割り当てられない場合に発生する以下の処理のことです。
・メモリから溢れたプロセスをストレージに移動 (スワップアウト)
・ストレージに存在するプロセスを CPU で処理するために、メモリに移動 (スワップイン)
ストレージへのアクセスは、CPU の動作と比較してとても遅いので、スワップが発生するとコンピュータの性能は低下します。
なお、現在では「スワッピング (スワップ)」と「ページング」はほぼ同義です。
1960年代にセグメント方式とページング方式の仮想記憶の概念が登場すると、「スワッピング」という用語はセグメント単位およびページ単位の二次記憶と主記憶間の転送を意味するようになった。今日の仮想記憶はほとんどがページング方式となったため、「スワッピング」は「ページング」とほぼ同義に使われることもある
https://ja.wikipedia.org/wiki/%E3%83%9A%E3%83%BC%E3%82%B8%E3%83%B3%E3%82%B0%E6%96%B9%E5%BC%8F
ページ化セグメンテーション方式
以下のように、セグメントごとにページテーブルを用意します。

ページング方式とセグメント方式をのいいとこ取りのため、物理メモリで発生する以下の全ての問題に対応可能です。
- プロセスサイズの制約 (物理メモリに乗り切らない分は、ストレージに置いておく)
- フラグメンテーション (仮想メモリ上では連続している。ページ単位で物理メモリにマッピング可能)
- 他プロセスのメモリ領域の破壊 (別のプロセスが利用中の物理アドレスに対するマッピングを禁止)
- 自プロセス内のメモリ領域の破壊 (別のセグメントに書き込み禁止 = セグメンテーションフォールト)
Out Of Memory(メモリ不足)
OOM (Out Of Memory) は、「メモリ・ストレージのスワップ領域」が埋まった状況で、メモリを確保すると発生するエラーです。
OOM は仮想メモリの方式によらず、メモリとスワップ領域がいっぱいになると発生します。
システムは開放可能なメモリを解放することで Out Of Memory を回避します。
もし、開放可能なメモリが存在しない場合、OOM Killer が発生します。
OOM Killer は、Linux カーネルが適当なプロセスを選択して kill(強制終了)します。
最後に
Linux カーネル「メモリ管理」に関する説明は以上となります。
その他の Linux カーネルの機能について知りたい場合は以下の記事をどうぞ。
- 【Linux カーネル: OS 入門1】OS、カーネルとは
- 【Linux カーネル: OS 入門2】CPU・プロセス管理
- 【Linux カーネル: OS 入門3】メモリ管理 ←イマココ
- 【Linux カーネル: OS 入門4】ストレージ管理・ファイルシステム
- 【Linux カーネル: OS 入門5】ファイルシステムの機能一覧
- 【Linux カーネル: OS 入門6】I/O デバイス管理
参考書籍
以下の書籍を参考にしました。
参考サイト
以下のサイトを参考にしました。