コンテンツにスキップ

1-2. プログラムが動く仕組み

  • ソースコードが実行されるまでの流れ
  • コンパイルとインタプリタの違い
  • スタックとヒープの仕組み
  • スレッドとプロセスの違い

プログラマーが書く「ソースコード」は、そのままではCPUは理解できない。CPUが理解できるのは 機械語(マシン語) のみ。

ソースコード → 変換 → 機械語 → CPUが実行
(人間が読める) (0と1の羅列)

実行前にソースコード全体を機械語に変換する方式。

ソースコード
▼ コンパイラ(翻訳ツール)
機械語ファイル(実行ファイル)
▼ 実行
  • 代表言語:C, C++, Rust, Java(バイトコードに変換)
  • メリット:実行が速い(変換済みのため)
  • デメリット:実行前にコンパイルが必要。エラーも事前にわかる

コードを1行ずつ読みながらその場で実行する方式。

ソースコード
▼ インタプリタ(逐次実行)
実行(行ごと)
  • 代表言語:Python, Ruby, JavaScript(ブラウザやNode.jsで実行)
  • メリット:すぐに実行できる。対話的な操作も可能
  • デメリット:コンパイル方式に比べて実行が遅い

Javaは「コンパイル」と「インタプリタ」の中間的な方式を採用している。

Javaソースコード(.java)
▼ javac(Javaコンパイラ)
バイトコード(.class) ← 機械語ではなく中間コード
▼ JVM(Java Virtual Machine)が実行
  • バイトコードはOSに依存しない → どのOS上でも同じコードが動く(Write Once, Run Anywhere)
  • JVMがバイトコードを各OSの機械語に変換しながら実行する

プログラムが実行される際、メモリは主に2つの領域に分かれて使われる。

メモリの構造
┌──────────────────┐ ← 高アドレス
│ スタック │ ← 関数の呼び出しや
│ (Stack) │ ローカル変数を保存
│ │
│ ↓ 伸びる │
│ │
│ ↑ 伸びる │
│ │
│ ヒープ │ ← 動的に確保するデータ
│ (Heap) │
├──────────────────┤
│ 静的領域 │ ← グローバル変数など
├──────────────────┤
│ コード領域 │ ← プログラム本体
└──────────────────┘ ← 低アドレス
  • 特徴:後入れ先出し(LIFO: Last In, First Out)の構造
  • 用途:関数の呼び出し情報・ローカル変数
  • 管理:自動的に確保・解放される
  • サイズ:小さい(通常数MB)
// 関数呼び出しのイメージ
function main() { // スタックに main のフレームを積む
int x = 10;
greet(); // スタックに greet のフレームを積む
} // main のフレームが取り除かれる
function greet() {
String msg = "Hello"; // スタックに msg を積む
} // greet のフレームが取り除かれる

スタックオーバーフロー(StackOverflow)は、関数が無限に呼び出され続けてスタックが満杯になったときに発生する。

  • 特徴:自由に確保・解放できる
  • 用途:実行時に動的に作成されるオブジェクト
  • 管理:プログラムまたはGCが管理する
  • サイズ:大きい(GBオーダーも可能)
// Java の例
String name = new String("Alice");
// "Alice" というオブジェクトはヒープに確保される
// Java ではGC(ガベージコレクタ)が自動的に解放してくれる

JavaやJavaScriptなどは ガベージコレクタ が不要になったメモリを自動的に解放する。 C/C++ではプログラマが手動でメモリを解放する必要があり、解放忘れると メモリリーク が発生する。


OSが管理するプログラムの実行単位。

  • それぞれ独立したメモリ空間を持つ
  • プロセス同士はメモリを共有しない(直接干渉できない)
  • 例:ブラウザ、エディタ、ターミナルは別々のプロセス
OSが管理するプロセス一覧
PID プロセス名
1234 Chrome
5678 VSCode
9012 Terminal

プロセスの中でさらに並行して動く実行単位。

  • 同じプロセス内のスレッドはメモリを共有する
  • 複数スレッドで同時に処理を進められる(並列処理)
プロセス(Chrome)
├── スレッド1: タブのレンダリング
├── スレッド2: ネットワーク通信
└── スレッド3: JavaScriptの実行

シングルスレッド vs マルチスレッド

Section titled “シングルスレッド vs マルチスレッド”
種類特徴代表
シングルスレッド1つずつ処理。シンプルで安全JavaScript(メインスレッド)
マルチスレッド複数の処理を同時進行。高速だが複雑Java, C++

JavaScriptはシングルスレッドだが、イベントループの仕組みで非同期処理(時間のかかる処理を待っている間に別の処理を進める)を実現している。

console.log("1番目");
setTimeout(() => {
console.log("3番目(1秒後)");
}, 1000);
console.log("2番目");
// 出力:
// 1番目
// 2番目
// 3番目(1秒後)

4. プログラムが実行されるまでの全体像

Section titled “4. プログラムが実行されるまでの全体像”
1. ソースコードを書く(.java / .js など)
2. コンパイル or そのまま(言語による)
3. OSがプログラムを読み込みプロセスを作成
4. OSがメモリ(スタック・ヒープ)を確保
5. CPUがコードを1命令ずつ実行
6. 処理が終わるとOSがプロセスを終了し、メモリを解放

キーワード説明
コンパイル実行前にソースコードを機械語に変換する
インタプリタコードを1行ずつ実行する
バイトコードJavaのJVM用の中間コード
スタック関数呼び出しやローカル変数を保存するメモリ領域
ヒープ動的に確保するオブジェクトを保存するメモリ領域
GC不要になったメモリを自動解放する仕組み
プロセスOSが管理するプログラムの実行単位
スレッドプロセス内で並行して動く処理の単位

演習問題 に取り組んで理解を確認しよう。

理解できたら 1-3. コマンドライン基礎 へ進もう。