【Linux カーネル: OS 基礎入門3】メモリ管理

Linux

本記事は全5回に渡る Linux カーネルの解説のうち第3回「メモリ管理」に関する記事です。

その他の Linux カーネルの解説については以下の記事をご覧ください。

メモリとは

メモリとは、CPU が直接読み書きできるものです。実行中のプロセスを置いたり、データを置いたりするために利用します。

なお、本記事で記載する「メモリ」は「メインメモリ」を表します。

その他のメモリの種類については以下に記載します。

メモリの種類

メモリには以下の3種類があります。

  • キャッシュメモリ
  • メインメモリ(主記憶装置/Primary Memory)
  • ストレージ(補助記憶装置/Secondary Memory)

レジスタを含めたそれぞれのメモリの比較は以下のとおりです。

図1:レジスタとメモリの比較

キャッシュメモリ

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

「図1:レジスタとメモリの比較」に記載のとおり、高速アクセス、低用量であることから、CPU が頻繁にアクセスするメインメモリのデータをキャッシュメモリにキャッシュします。

メインメモリ(揮発性メモリ/主記憶装置/Primary Memory)

メインメモリは、CPU が実行中のプログラム(プロセス)を置くために利用します。

メインメモリは以下の特徴を持ちます。

  • 揮発性(電源を切るとデータが消える)
  • キャッシュメモリより遅く、ストレージより早い
  • メインメモリ無しでコンピュータを実行することは出来ない
    • CPU は実行中のプロセスやデータをメインメモリに置くため

ストレージ(不揮発性メモリ/補助記憶装置/Secondary Memory)

ストレージはデータを永続的に保存する(電源を切っても消えない)ために利用します。

CPU はストレージに直接アクセスしません。CPU がストレージのデータにアクセスする場合は、以下の手順となります。

  1. データをストレージからメインメモリに転送
  2. CPU はメインメモリ上のデータにアクセス

ストレージの特徴は以下のとおりです。

  • 不揮発性(電源を切ってもデータが消えない)
  • メインメモリより遅い
  • ストレージ無しでコンピュータを実行することも可能

メモリ使用率や内訳を確認 free

free コマンドを利用することで、メインメモリ使用率、および内訳を確認することができます。

free
              total        used        free      shared  buff/cache   available
Mem:        8063684      358512     7180624         652      524548     7473952

メモリを使用してみる

今回は /dev/shm にマウントされた共有メモリを利用します。

df -Th
ファイルシス   タイプ   サイズ  使用  残り 使用% マウント位置
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 利用してみます。

free
              total        used        free      shared  buff/cache   available
Mem:        8063684      358512     7180624         652      524548     7473952
dd if=/dev/zero of=/dev/shm/tempfile bs=1M count=2048
2048+0 レコード入力
2048+0 レコード出力
2147483648 バイト (2.1 GB) コピーされました、 0.899953 秒、 2.4 GB/秒
free
              total        used        free      shared  buff/cache   available
Mem:        8063684      362620     5043644     2097804     2657420     5370028

free と Available が 2GiB 減少し、shared, buff/cache が 2GiB 増加したことがわかります。

メモリが揮発性であることを確認

再起動し、メモリの内容が消えることを確認します。

df -Th
tmpfs          tmpfs      3.9G  2.0G  1.9G   53% /dev/shm
sudo reboot
df -Th
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回で済むためです。

バーチャルメモリ(仮想記憶)

バーチャルメモリとは、プロセスから見たメモリのことです。
実際のデータは、メインメモリ + ストレージのスワップ領域に保存されます。

Secondary Memory(ストレージ)の中でも、特にスワップ領域に保存

なお、仮想アドレス(Virtual Adress)と対比して、メインメモリのアドレス空間を物理アドレス(Physical Adress)と呼びます。

バーチャルメモリが必要な理由は以下の3つです。

  • メインメモリより大きなサイズのプロセスを起動可能
  • メインメモリを保護可能(別プロセスからの上書きを避ける)
  • マルチプロセスの実装が容易

メインメモリより大きなサイズのプロセスを起動可能

  • プロセスをメインメモリへマッピング
  • 溢れた容量はストレージにマッピング
  • CPU がストレージにあるデータを処理する場合はスワッピング

メインメモリを保護可能(別プロセスからの上書きを避ける)

  • 他のプロセスが存在する物理アドレスにはマッピングを避ける
  • カーネル用の物理アドレスにマッピングを避ける

マルチプロセスの実装が容易

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

バーチャルメモリの実装

バーチャルメモリは次の2つの方式で実装されます。

  • ページング方式
  • セグメント方式

なお、CPU がバーチャルメモリを利用してメインメモリにアクセスする場合は、MMU(Memory Management Unit)と呼ばれるハードウェアが仮想アドレスから物理アドレスへの変換します。

ページング方式

ページング方式は、プロセスの仮想アドレス空間を"ページ"と呼ばれる固定サイズのブロックに分割するメモリ管理手法です。
各ページがメインメモリのどの物理アドレスにマッピングされているか記録したものをページテーブルと呼びます。

なお、ページサイズは getconf PAGESIZE コマンドで確認可能です。

getconf PAGESIZE
4096

以降の例ではわかりやすいようにページサイズは 100Bytes で説明します。

ちなみに、CPU が仮想アドレス 200-300 にアクセスした場合、ページフォールトが発生しストレージからメインメモリに対象データがスワップインされます。

また、カーネル領域や既に別プロセスが稼働する物理アドレスにマッピングした場合はセグメンテーションフォールトが発生します。

セグメント方式

セグメント方式とは、プロセスの仮想アドレス空間を"セグメント"と呼ばれる可変サイズのブロックに分割するメモリ管理手法です。
セグメントとは、あるルールによってグループ分けされるデータのことです。

各セグメントは異なるサイズであることがわかります。

なお、プロセスの各セグメントの意味は以下の記事をご覧ください。

なお、各セグメントがページで分割されている方式をページ化セグメンテーションといいます。

ページ置換アルゴリズム

ページ置換アルゴリズムとは、ページフォールト(メインメモリにデータが無いこと)が発生した際に、どのページをストレージのデータと置換(スワッピング)するか決める方法のことです。

ページフォールトが増加するとスワッピングが発生すると処理が遅くなります。

そのため、ページフォールトの発生が低いページ置換アルゴリズムは良いアルゴリズムと言えます。

代表的なページ置換アルゴリズム2つを紹介します。

  • First In First Out (FIFO) algorithm
  • Least Recently Used (LRU) algorithm

その他のアルゴリズムについては wiki にまとまっているのでご覧ください。

ページ置換アルゴリズム - Wikipedia

First In First Out (FIFO) algorithm

一番古いページを置き換えるアルゴリズムです。

https://www.tutorialspoint.com/operating_system/os_virtual_memory.htm

Least Recently Used (LRU) algorithm

最も長く使用していないページが置換されます。

FIFO と異なり、古いページでも最近利用されている場合は置換されません。

https://www.tutorialspoint.com/operating_system/os_virtual_memory.htm

最後に

Linux カーネル「メモリ管理」に関する説明は以上となります。

その他の Linux カーネルの機能について知りたい場合は以下の記事をどうぞ。

参考書籍

以下の書籍を参考にしました。

参考サイト

以下のサイトを参考にしました。

Operating System - Memory Management - Tutorialspoint
Operating System - Memory Management - Memory management is the functionality of an operating system which handles or manages primary memory and moves processes...
0

コメント