Stack と Heap の違いを“図解付き”でやさしく理解する【Java内部構造の基礎】

🧠 【初心者向け】Stack と Heap の違いをやさしく解説

Java プログラムが動く裏側では、
Stack(スタック)Heap(ヒープ) という2つのメモリ領域が常に働いています。

「何となく聞いたことはあるけど、結局どう違うの?」
「StackOverflowError とか GC とか、いまいち仕組みが分からない…」

そんな声をよく聞くので、
この記事では 図解とシンプルな例 を使って、
Stack と Heap の違いを “はじめてでも分かる形” で整理します。

結論

・Stack は「メソッドの作業スペース」(高速・自動破棄)

・Heap は「new したオブジェクトの置き場」(柔軟・GCで管理される)

とりあえずこの図を見てほしい👇

┌──────────┐      ┌────────────┐
│ Stack              │      │  Heap                  │
│ ・ローカル変数     │      │ ・newした実体          │
│ ・参照だけ置く     │      │ ・List / Stringなど    │
└──────────┘      └────────────┘
       ↑ 高速                       ↑ 大きく柔軟

Stack=「机」
Heap=「倉庫」
と覚えるとイメージしやすいです。


Stack とは?(初心者向けの基本説明)

Stack は メソッド1つにつき1つの“作業スペース”が積み重なる領域 です。

🔹 メソッド呼び出しの流れ(図解)

main() 呼び出し
  ↓
┌──────────┐
│ Frame: main        │
│ int x = 10         │ ← Stackに置かれる
└──────────┘

run() 呼び出し
  ↓
┌──────────┐
│ Frame: run         │
│ User u             │ ← 参照をStackに置く
└──────────┘

特徴:

  • 小さく高速
  • メソッド終了と同時に 一瞬で破棄
  • 消し忘れ不可(自動管理)

Heap とは?(初心者向けの基本説明)

Heap は new で作ったオブジェクトの実体が置かれる倉庫 です。

┌────────────┐
│ Heap                   │
│   new User()           │ ← 実体はここ
│   new ArrayList()      │
│   new int[100]         │
└────────────┘

Heap の特徴:

  • 大容量
  • 柔軟にオブジェクトを配置できる
  • 不要になったら GC(ガーベジコレクション) が回収
  • Stack より遅い(距離が遠いイメージ)

利用時の注意点・落とし穴

❌ 誤解1:プリミティブはStack、参照型はすべてHeap

→ 正しくは
参照は Stack、実体は Heap

❌ 誤解2:Stack のほうが速い=全部Stackに置けば速い

→ Stack はサイズ固定でオブジェクトを置けない

❌ 誤解3:Heap は参照が消えた瞬間に解放される

→ GC のタイミング次第。即時解放ではない


ここまでのまとめ(初心者向け)

[Stack]
・メソッド呼び出し  
・参照  
・ローカル変数  
・高速&自動破棄

[Heap]
・newしたオブジェクト  
・柔軟だが遅め  
・GCが管理

最重要ポイントは
参照は Stack、実体は Heap
です。


▼▼ ここから深掘り・ニッチ編 ▼▼


【後半:ニッチ編】Stack と Heap の内部構造

Java の実行時、Stack と Heap は JVM によって厳密に管理されています。
その内部イメージを図解で見ていきましょう。


内部構造:Stack は「スタックフレーム」の積み重ね

メソッド呼び出しごとに “スタックフレーム” が積まれます。

┌─────────┐
│ Frame: calc      │  ← 上に積まれる
│  ローカル変数    │
└─────────┘
┌─────────┐
│ Frame: main      │
└─────────┘

深すぎる再帰で
StackOverflowError が起きるのはこの構造のせい。


内部構造:Heap は「世代別(Young / Old)」で管理される

Heap は以下のように分割されています👇

Heap
├ Young Generation(短命が多い)
│   ├ Eden
│   └ Survivor(S0 / S1)
└ Old Generation(長寿オブジェクト)

🔹 GC が効率よく回る理由

  • オブジェクトの大半はすぐ死ぬ(Eden で回収)
  • 生き残る個体だけ Old に昇格(Promotion)
    → メモリ回収が効率化される

パフォーマンス最適化のポイント

✔ ArrayList / StringBuilder の初期容量は重要

拡張=Heap再割り当てが発生するためコストが重い。

✔ 参照が残ると GC できない

静的フィールドやキャッシュに残り続けるパターンは典型的なメモリリーク。

✔ new のしすぎで若い世代GC(Minor GC)が多発すると遅い

オブジェクト生成は安いが、多すぎると積もる。


スレッド・安全性の観点

ThreadA → StackA  
ThreadB → StackB  
                  ↓
                 Heap(共有)
  • Stack はスレッドごとに分離(安全)
  • Heap は共有(競合のおそれ)
    → synchronized や volatile が登場する理由はここにある

この記事のまとめ

  • Stack=高速な「作業台」
  • Heap=柔軟な「倉庫」
  • 参照は Stack、実体は Heap
  • Heap は GC によって賢く管理される
  • スレッドとメモリ領域の関係も重要

Deep Friendly Tech の一言(後書き)

Stack と Heap を理解すると、
「このコードはなぜ速い/遅いのか」
「このバグはなぜ起きるのか」
といった コードの本質が読めるエンジニア になります。

この基礎理解は Java だけでなく、
Go・Python・C#・C++・Rust にも応用できます。

コメント

タイトルとURLをコピーしました