Web Analytics Made Easy - StatCounter

工業大学生ももやまのうさぎ塾

うさぎでもわかるをモットーに大学レベルの数学・情報科目をわかりやすく解説! 数式が読み込まれない場合は1回再読み込みしてみてください。

うさぎでもわかる計算機システム Part13 4つのメモリ領域・システムコール

こんにちは、ももやまです。

今回はの4つのメモリ領域とシステムコールの2つについてまとめていきたいと思います。

前回の計算機システムの記事(Part12)はこちら!

www.momoyama-usagi.com

1.4つのメモリ領域の種類

メモリの領域は、実行するプログラムがどのように使われるかによっていくつかの領域にわけることができます。

例えば、C言語で書かれたプログラムであれば

  • テキスト領域(プログラム領域)
  • データ領域
  • ヒープ領域
  • スタック領域

の4つに分けることができます。

また、データ領域は変数が初期化されるかどうかで、

  • データ領域(初期化あり)
  • bss領域(初期化なし)

の2つにさらに分割し、合計5つの領域として考えることもできます。

2.静的変数・広域変数・局所変数などの復習

念の為、C言語の様々な変数の復習をしてみましょう。

復習にあたってサンプルプログラムを1つ用意しました。

int n = 100; // 広域変数(グローバル変数)

void test() {
    int x = 0; // 局所変数
    static int y = 0; // 静的変数(2回目以降は初期化されない)
    // x は局所変数、y は静的変数である

    x += 1;
    y += 1;

    printf("x:%2d  y:%2d\n",x,y);
}

(1) 静的変数 (static 変数)

静的変数とは、2回目以降同じ関数を実行した際に初期化されない変数を表します。

例えば、上の関数 test を5回実行すると、x は何回実行しても1ですが、y は実行された回数分の値、つまり5が出力されます。


C言語の場合、型の前に static をつけることで静的変数を宣言することができます。

例えば、変数 y を静的変数の int 型で宣言したい場合、static int y; とすることで宣言できます。


(2) 広域変数 (大域変数・グローバル変数)

広域変数とは、どの関数からも使うことができるような変数のことを表します。

グローバル変数・大域変数と呼ばれることもあります。


例えば、上にあるプログラムの n は関数の外で宣言されていますよね。

このように、関数の外で変数を宣言することで広域変数を宣言することができます。

(3) 局所変数

局所変数とは、1つの関数だけから使うことができるような変数を表します。


例えば、上にあるプログラムの x, y は関数 sum1_n の中で宣言されていますよね。そのため、関数 test でのみ使用することができます。

言い方を変えると、ある関数 f1y を宣言し、別の関数 f2y を宣言しても、f1 の中にある変数 yf2 の中にある y は別の変数として扱われます。


このように関数の中で宣言した変数は、宣言した関数内でしか効力を持ちません。

3.メモリ領域の分け方

まずはC言語ではどのように4つ(5つの)領域を使い分けているかを図で確認しましょう。

f:id:momoyama1192:20191206234824g:plain

※データ領域とbss領域を1つにまとめてデータ領域とすることもあります。この場合だとメモリ領域は4つに分けられます。

では実際に4つ、5つの領域について少し詳しく説明しましょう。

(1) テキスト領域(プログラム領域)

テキスト領域には、プログラムの中で機械語の部分、つまりCPUの命令コードが格納されている領域です。

また、テキスト領域は読み出し専用となので、プログラム上でテキスト領域に書き込もうとすると割り込みが発生します

(2-1) データ領域

プログラムの中で初期値をもつような変数に割り当てられる領域です。

C言語では、0以外の初期値をもつ静的変数・広域変数に割り当てられます。

(2-2) bss領域

プログラムの中で初期値をもたない(指定しない)ような変数に割り当てられる領域です。

C言語では、初期値が0の静的変数・広域変数に割り当てられます。

データ領域・bss領域の2つを合わせてデータ領域として考えることも多くあります。この場合、データ領域は静的変数や広域変数に割り当てられる領域となります。

(3) ヒープ領域

動的にメモリ領域の確保や解放を行うのがヒープ領域です。

C言語では、malloc() 、C++では new 演算子により確保されたメモリ領域がヒープ領域となります。

動的にサイズが確保されるため、実行中にヒープ領域のサイズが変化します。

また、ヒープ領域のアドレスは先に確保したものから小さい順に割り当てられます。

(4) スタック領域

関数内にある局所変数や、関数への引数、戻り値などに割り当てられるのがスタック領域です。

C言語では、static 変数でない局所変数、および関数への引数や戻り値に割り当てられます。


ヒープ領域と異なり、実行中にスタック領域のサイズは変化しません。

そのため、変数を宣言しすぎたり、あまりにも大きな配列などを宣言するとクラッシュし、Segmentation Fault が出ます。


また、スタック領域のアドレスは、ヒープ領域とは逆で、先に確保したものから大きい順に割り当てられます。

4.システムコール

最後にシステムコールについて簡単にですが説明したいと思います。

(1) システムコールとは

OSがプログラム(アプリケーション)に対して提供する機能を呼び出すことをシステムコールといいます。

少し言い換えると、OS側が提供している関数(API)をプログラムを使うことをシステムコールと呼びます。

(2) システムコールの種類

システムコールには、例えば以下のようなものがあります。

  • ファイルの読み込み・上書き・生成・削除・名前の変更などのファイル操作
  • メモリの割り当て
  • スリープ操作(実行までxx秒待機させるなどの命令)

(3) システムコールを使う理由

システムコールを使う2つの理由として

  1. ハードウェアを操作するためのシンプルなインターフェースを使える
  2. OSのリソースの保護

があります。

理由その1

ハードウェアを操作するためのシンプルなインターフェースを使えることで、プログラムを書く人はハードウェアの詳しい知識なしにシステムコールを使うことができます。

理由その2

ファイル操作やメモリ割り当てなどの操作は、失敗すると他のプロセス、さらにはOSまで影響が出てしまうことがあります。

そこでシステムコールを使うことにより、ファイル操作やメモリ割り当てなどの操作を安全に(OSを保護しながら)実現することができます。

(3) システムコールと割り込み

システムコールでは、「ファイル操作」や「メモリ割り当て」などの特殊な命令を行うこともあるため、非特権モードではシステムコールが実行できません。

そのため、割り込みを行い、非特権モードから特権モードに変更してからシステムコールが実行されます。

5.さいごに

今回は4つのメモリ領域とシステムコールについて簡単にですが説明しました。

次回からはUnixのファイルシステムについて何回かにわけて説明していきたいと思います。