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

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

なお、本記事は以下の書籍を参考にしています。

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

スポンサーリンク

メモリとは

メモリとは、CPU が直接読み書きできる記録デバイスです。
メモリは、プロセス(実行中のプログラム)を置くために使います。

プロセスについては以下の記事で解説していますので、詳細を知りたい方はご覧ください。

メモリ使用率の確認コマンド

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

メモリ管理とは

メモリ管理とは、以下のカーネルの機能のことです。
プロセスメモリを割り当てる方法 (仮想メモリ)
・不要なプロセスメモリから開放 (ページングスワップOOM Killer)

カーネルについては以下の記事で解説していますので、詳細を知りたい方はご覧ください。

スポンサーリンク

メモリ管理をする上での問題点

メモリでプロセスを管理する上で問題となることは、主に以下の4つです。

プロセスサイズの制約

プロセスサイズがメモリサイズより大きくなる場合、メモリ不足によりプログラムは起動できません。

プロセスが大きすぎて、メモリに置けない

フラグメンテーション

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

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

プロセスは 200Bytes で、メモリの合計空き容量は 200 Bytes
しかし連続した空き容量は 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 コマンドで確認可能です。

getconf PAGESIZE
4096

ページフォールト/ページング

ページフォールトは、物理メモリ上にページが見つからない状態を表します。

例えば、CPU が仮想アドレス 300-400 にアクセスするとページフォールトが発生します。

カーネルはページフォールトを検出するとページングと呼ばれる以下の2つの処理を行います。

なお、ページアウトするページは、ページ置換アルゴリズムによって選択されます。

ページフォールトが増加し、ページングが頻発するとストレージへのアクセスが頻発するため、処理が遅くなります。そのため、ページフォールトの発生が低いページ置換アルゴリズムは良いアルゴリズムと言えます。

代表的なページ置換アルゴリズム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

セグメント方式

セグメント方式は、「セグメント (データ分類ごと)」でメモリを分割する方式です。

プロセスは次の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

ページ化セグメンテーション方式

ページング方式セグメント方式を組み合わせた方式です。

以下のように、セグメントごとにページテーブルを用意します。

参考資料:http://www.matlab.nitech.ac.jp/~matsuo/OS/OS10.pdf

ページング方式セグメント方式をのいいとこ取りのため、物理メモリで発生する以下の全ての問題に対応可能です。

Out Of Memory(メモリ不足)

OOM (Out Of Memory) は、「メモリストレージのスワップ領域」が埋まった状況で、メモリを確保すると発生するエラーです。

OOM は仮想メモリの方式によらず、メモリとスワップ領域がいっぱいになると発生します。

システムは開放可能なメモリを解放することで Out Of Memory を回避します。

もし、開放可能なメモリが存在しない場合、OOM Killer が発生します。

OOM Killer は、Linux カーネルが適当なプロセスを選択して kill(強制終了)します。

最後に

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

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

参考書籍

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

参考サイト

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

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