雖然 .NET 執行期(CLR)提供自動記憶體管理,但理解堆疊與堆積的運作機制、值類型與參考類型的儲存差異、垃圾回收器(GC)的代演算法,以及 IDisposable 模式,對撰寫高效能、無記憶體洩漏的程式至關重要。本文系統整理核心觀念與實務技巧。
| 特性 | 堆疊 | 堆積 |
|---|---|---|
| 資料結構 | LIFO(後進先出),像疊盤子 | 動態分配,可隨機存取 |
| 存放內容 | 方法呼叫框架、區域變數(值類型)、參數、回傳位址 | 參考類型實例(物件)、陣列、字串、boxed 值類型 |
| 生命週期 | 方法結束自動釋放 | 由 GC 追蹤根參考,非預期性回收 |
| 效能 | 極快(指標移動) | 較慢(分配、壓縮、代檢查) |
int、struct、enum、bool 等):預設儲存在宣告處的堆疊;若為參考類型的欄位,則隨物件在堆積。class、interface、delegate、string、陣列):物件本體在堆積,變數(參考)在堆疊。// 傳值:複製值類型內容(大型 struct 效能差)
void AddFive(int pValue) { pValue += 5; }
// 傳參考:複製參考(指標),雙方指向同一物件
void Modify(MyClass obj) { obj.Prop = 10; }
// ref/out 傳值類型參考:避免大型 struct 複製
void DoSomething(ref MyStruct s) { ... }
// ref 傳參考類型:可替換呼叫端的物件參考
void Switcharoo(ref Thing t) { t = new Vegetable(); }
參考類型成員若僅複製參考,會導致雙方共用同一子物件(如 Shoe 範例)。實作 ICloneable 並在 Clone() 中遞迴複製所有參考成員,才能獲得真正獨立的深複製。
~Class()):GC 呼叫,非決定性、延遲、需兩次 GC 週期、效能負擔大。僅作為安全網。using 區塊(編譯為 try/finally),立即釋放檔案、資料庫連線、GDI 物件等。Dispose(bool disposing),Dispose() 呼叫 Dispose(true) 並 GC.SuppressFinalize(this);Finalizer 呼叫 Dispose(false)。using 區塊、try/finally 確保 Dispose() 執行。ArrayPool、StringBuilder、MemoryStream 重用。List.Clear() 僅移除元素,容量不釋放;需 list = new List() 或 TrimExcess()。StringBuilder。Task/async 狀態機捕獲區域變數 → 延長生命週期 → 注意閉包捕獲。深入掌握記憶體模型,不只是面試題,更是寫出穩健、高效 .NET 應用程式的基石。