在開發C#應用程式時,我們常常聽到「多執行緒(Multi-threading)」能提升效能,也知道物件和變數會被分配到「堆疊(Stack)」與「堆積(Heap)」中。
但你是否曾深入思考過:當多個 Thread 同時執行時,它們在記憶體中究竟是如何互動的?
Thread是程式執行的最小單位。
把一個程式(Process)想像成一家公司:
Process = 公司
Thread = 員工
using System.Threading.Tasks;
Task.Run(() =>
{
Console.WriteLine("Download File");
});
Task.Run(() =>
{
Console.WriteLine("Play Music");
});
此時:
Thread 1 負責下載檔案
Thread 2 負責播放音樂
兩件事情可以同時進行。
Stack是每個Thread自己擁有的記憶體空間。
主要存放:
區域變數(Local Variables)
函式參數
函式呼叫資訊
返回位置
void Attack()
{
int damage = 50;
float criticalRate = 0.2f;
}
當Attack()被呼叫時:
┌─────────────────┐
│ criticalRate │
│ 0.2 │
├─────────────────┤
│ damage │
│ 50 │
└─────────────────┘
函式結束Stack會自動回收。
Stack特性
✅ 存取速度快
✅ 自動管理
✅ 不需要手動釋放記憶體
❌ 空間較小
❌ 遞迴過深可能發生Stack Overflow
Heap是所有hread共用的記憶體區域。
通常用於存放:
Class 物件
陣列
較大型資料結構
遊戲中的角色、道具、怪物
class Player
{
public int HP;
}
Player player = new Player();
player.HP = 100;
記憶體概念:
Stack Heap
┌──────────┐
│ player ──┼──────────► Player
└──────────┘ HP = 100
Stack 裡只有參考(Reference)。
真正的物件存在 Heap。
Heap特性
✅ 空間大
✅ 物件生命週期較長
✅ 可被多個物件共享
❌ 存取速度較慢
❌ 容易產生大量GC(Garbage Collection)
每個Thread都有自己的Stack。
Process
├─ Thread A
│ └─ Stack A
│
├─ Thread B
│ └─ Stack B
│
└─ Heap
//如果兩個 Thread 同時執行:
Task.Run(Work);
Task.Run(Work);
//兩個 count 完全獨立。
Heap是共享的。
class Player
{
public int HP = 100;
}
Player player = new Player();
//Thread A
player.HP -= 10;
//Thread B
player.HP -= 20;
//兩個Thread都在修改同一個物件:
Thread A ──┐
│
▼
Player
HP = 100
▲
│
Thread B ──┘
可能產生:
Race Condition(競爭條件)
Data Race(資料競爭)
因此會需要以下方式,來保護共享資料。
//未來將補充
lock
Monitor
Mutex
Interlocked
掌握Thread與記憶體配置的基本概念,就像打好程式設計的地基。雖然在初學階段不需要馬上深入到多執行緒的細節,但理解Stack與Heap的差異,能幫助我們更清楚程式在背後的運作方式。等到未來進一步學習並處理複雜的並行程式設計時,這些基礎知識就會成為不可或缺的工具。