0. はじめに
名作の多い「なぜシリーズ」の書籍のひとつである、プログラムはなぜ動くのかを読みましたので、参考になった点や教育に使いたい点をまとめてみました。
1. プログラムが実行されるまで
プログラミングをしてからアプリケーションが実行されるまで流れは以下のようになる。
1-1. プログラミング
- プログラマがプログラム(ここではコンパイラ型言語)を記述する。
1-2. ビルド
- ビルドすると、プリプロセス→コンパイル→リンク(後術)が行われ、最終的に実行ファイル(.exeなど)が作成される。
- 実行ファイルの内容は、マシン語のネイティブコードとなる。
- ネイティブコードはCPUが解釈できるコード。ソースコードそのままでは解釈できない。
1-2-1. プリプロセス
- プリプロセッサを利用し、「定数の置き換え」「コメントの削除」「マクロの展開」などを行う。
1-2-2. コンパイル
- コンパイラを利用し、プログラムをオブジェクトファイル(.oや.objなど)に変換する。
1-2-3. リンク
- リンカを利用し、各オブジェクトファイルやライブラリのリンクを行う。
- ライブラリは複数のオブジェクトファイルをまとめて1つに格納したファイルのこと。
1-3. メモリに乗せる
- 実行ファイルを実行することで、ネイティブコードのコピーがメモリに乗る。
- DLLファイルは実行時に結合される。
1-4. CPUが動かす
- CPUがメモリ上のネイティブコード(命令やデータ)を解釈しながら実行する。
2. CPU
2-2. CPUを構成する4つの機能
CPUは以下の4つの機能から構成される。
2-2-1. 制御装置
- メモリ上の命令やデータをレジスタに読み出し、命令の実行結果に応じてコンピュータ全体を制御する。
- データのやり取りは、必ず制御装置を通して行われる。
2-2-2. 演算装置
- レジスタに読み出されたデータを演算する。
2-2-3. クロック
- CPUが動作するタイミングとなるクロック信号を発生させる。
- クロック周波数(クロック信号の速さ)が大きい程CPUの動作は早くなる。
2-2-4. レジスタ
- 処理対象となる命令やデータを格納する。
- プログラムはレジスタを対象として記述される。(詳しくはアセンブリ言語を勉強しよう)
- 主なレジスタは以下。
名前 | 数 | 説明 |
---|---|---|
アキュムレータ | 1つ | 演算を行うデータ、演算後のデータを格納する。 |
フラグレジスタ | 1つ | 演算処理後のCPUの状態を格納する。 |
プログラムカウンタ | 複数 | 次に実行する命令が格納されたメモリのアドレスを格納する。 |
ベースレジスタ | 複数 | データ用のメモリ領域の先頭アドレスを格納する。 |
インデックスレジスタ | 複数 | ベースレジスタからの相対アドレスを格納する。 |
汎用レジスタ | 1つ | 任意のデータを格納する。 |
命令レジスタ | 1つ | 命令そのものを格納する。CPUが内部的に使用する。 |
スタックレジスタ | 1つ | スタック領域の先頭アドレスを格納する。 |
3. メモリ
3-1. メモリの物理的な仕組み
- ピンの配置は以下。
- VCC/GND・・・電源のピン
- A0~A9・・・アドレス信号のピン
- D0~D7・・・データ信号のピン
- RD/WR・・・制御信号のピン
- ICのピン1本では、ON/OFFの2つの状態しか表せない。このため、コンピュータは情報を2進数で扱っている。
- VCC/GNDに電源を流し、その他のピンに0 or 1の信号を与える。
- データ信号のピンが8本あるため、一度に8ビットの(1バイト)のデータを入出力できる。
- アドレス信号のピンが9本あるため、000000000~111111111の1024通りのアドレスが指定できる。
- このメモリICには、1バイトのデータを1024個格納することができる。つまり1KBの容量を持つメモリとなる。(あくまで参考なのでこのサイズってことで)
3-2. メモリ上のプログラムのイメージ
メモリには、命令やデータを格納場所を示すアドレスが割り振られている。
以下にイメージを記載する。(ただし、実際には1つの命令やデータに対して複数アドレスまたがって使用される。)
アドレス | 種類 | メモリの内容 |
---|---|---|
0100 | 命令 | 0108番地の値をアキュムレータに格納せよ |
0101 | 命令 | 0109番地の値を汎用レジスタに格納せよ |
0102 | 命令 | アキュムレータの値に汎用レジスタの値を加算せよ |
0103 | 命令 | アキュムレータの値を500と比較せよ |
0104 | 命令 | 大きければ0106番地にジャンプせよ |
0105 | 命令 | アキュムレータの値に100加算せよ |
0106 | 命令 | アキュムレータの値をディスプレイに表示せよ |
0107 | 命令 | プログラムを終了せよ |
0108 | データ | 150 |
0109 | データ | 450 |
また、プログラムの流れは、主に以下の種類に分類される。
- 順次進行・・・アドレスの値の順に命令を実行する。
- 条件分岐・・・条件に応じて任意の命令を実行する。
- 繰り返し・・・同じアドレスの命令を何度か繰り返し実行する。
4. ディスク
4-1. プログラムはメモリから実行
- ディスクに保存されたプログラムは、メモリにロードされてから実行される。
- ディスクから直接ロードすることはできない。これは、CPUはメモリのアドレスを指定してプログラムを読み出すため。
4-2. ディスク・キャッシュ
- 一度ディスクから読み出したデータを保存しておく、メモリ内の領域のこと。
- 次に同じデータが読み出されるときは、ディスク・キャッシュ内のデータを読み出す。これにより、アクセス速度を向上できる。
4-3. 仮想記憶
- ディスクの一部を仮想的にメモリとして扱う。
- 仮想記憶により、メモリが不足している場合でもプログラムの実行ができる。(メモリが5MBしか残っていないのに、10MBのプログラムを実行できる)
- 但し、実際のメモリと仮想メモリを書き換えながらプログラムを実行しているに過ぎないので、速度は低下する。
5. プログラムの動作環境
5-1. OSとハードウェア
- プログラムが動作するには、OSとハードウェアが大きく関連する。
- 市販のアプリケーションには、動作環境として以下のような項目が書かれていることが多い。
- 対応OS・・・Windows〇
- CPU・・・〇GHz以上
- メモリ・・・〇GB以上
- ディスク・・・〇GB以上の空き容量
5-2. 仮想マシン
- プログラムはビルドするとネイティブコードが生成される一方、Javaをビルドするとバイトコードが生成される。
※@shiracamus 様から補足コメント頂きました。 - バイトコードの実行環境を仮想マシンと呼ぶ。仮想マシンは、バイトコードを逐次ネイティブコードに変換しながら実行する。
- 各OSやハードウェア毎にJava仮想マシンを作成しておくことで、同じバイトコードのアプリケーションがどの動作環境でも実行できる。
6. おわりに
書籍ではメモリやCPUの詳しい説明だけでなく、アセンブリ言語や圧縮関連の記事、さらにコラムなども書かれています。
興味のある方は、是非書籍の方もご覧ください。
また、同じなぜシリーズの以下の記事も合わせてご覧頂けますと幸いです。