C#垃圾回收用法(GC)通俗易懂版
C# 的垃圾回收(Garbage Collection,簡稱 GC)機制是 .NET 運行時(CLR)的一部分,用于自動管理內存,避免程序員手動釋放內存帶來的問題(如內存泄漏、懸掛指針等)。
底層實現(xiàn)由 CLR 的 GC 引擎負責,具有高效、安全、并發(fā)、分代等特點。
一、為什么需要GC?
想象你的程序是一座繁忙的倉庫:
- 每執(zhí)行
new Person()就在倉庫中存放一個“貨物”(對象) - 變量(如
person1)是綁在貨物上的“繩子”(引用) - 問題:貨物不再使用后,若不清理,倉庫遲早爆滿 → 程序崩潰!
C#的GC就是自動化倉庫管理員,默默幫你清掃垃圾、整理貨架,徹底告別C/C++時代的手動delete之痛。
二、GC核心四步工作流(超簡化版)

1. 暫停世界(Stop-The-World)
- GC發(fā)出指令:“所有線程立刻凍結!”
- 目的:防止標記過程中對象狀態(tài)被修改,確保數據一致性。
2. 標記階段(Mark):誰還在用?
從根對象(Roots) 出發(fā):
- 靜態(tài)變量(墻上固定的掛鉤)
- 局部變量(操作臺上的臨時掛鉤)
- CPU寄存器中的引用(管理員手中的繩子)
深度追蹤:
- 沿著每根“繩子”找到對象,再檢查對象內部的引用(如
person1.Dog),像波浪一樣擴散標記所有可達對象,并打上“存活”標簽。
3. 清掃階段(Sweep):扔掉垃圾
- 遍歷整個堆內存(倉庫)
- 所有未被標記的對象 → 直接回收其內存!
- (無任何引用指向 = 程序永遠無法訪問 = 安全刪除)
4. 壓縮階段(Compact):整理碎片
// 壓縮前:內存碎片化(空閑但分散) [對象A][空閑][對象B][空閑][對象C] // 壓縮后:對象緊密排列 [對象A][對象B][對象C][大塊連續(xù)空閑空間]
- 移動存活對象到連續(xù)地址
- 更新所有引用(確保“繩子”指向新位置)
- 關鍵作用:避免內存碎片,提升后續(xù)分配效率!
三、GC高效秘密武器:分代回收(Generations)
洞察規(guī)律:
“越新的對象,越容易變成垃圾;活得越久,越可能長壽。”
.NET將堆內存分為三代
| 代際 | 對象特點 | GC檢查頻率 | 回收成本 |
|---|---|---|---|
| Gen0 | 新創(chuàng)建的小對象(如臨時變量) | 非常高 | 低 |
| Gen1 | 經歷1次GC仍存活的對象 | 中等 | 中 |
| Gen2 | 長期存活對象(如全局緩存) | 非常低 | 高 |
工作策略:
- 新對象默認進入Gen0
- Gen0滿 → 觸發(fā)GC(僅回收Gen0,速度極快)
- Gen0存活對象晉升Gen1
- Gen1滿 → 回收Gen0+Gen1
- Gen2滿 → 完全GC(回收所有代,性能影響大)
優(yōu)勢:90%的垃圾在Gen0被回收,避免頻繁掃描老對象!
四、對開發(fā)者的關鍵啟示
1. 無需手動釋放,但需“斷開引用”
讓對象變垃圾的正確方式:
// 方法1:引用置空
person1 = null;
// 方法2:超出作用域(局部變量自動失效)
void CreateTempObject() {
var temp = new Object(); // 函數結束 → temp引用消失
}
// 方法3:重新賦值
person1 = new Person(); // 原對象失去引用2. 特殊資源需手動釋放!
GC只回收內存!文件句柄、數據庫連接等需通過IDisposable主動釋放:
// 正確姿勢:using自動調用Dispose()
using (var file = File.Open("test.txt"))
{
// 操作文件...
} // 離開區(qū)域自動關閉文件!
// 等價于手動try-finally
try {
var file = File.Open("test.txt");
// ...
} finally {
file?.Dispose();
}3. 性能敏感場景優(yōu)化建議
- 避免高頻創(chuàng)建臨時對象(如循環(huán)內
new) - 慎用
GC.Collect()(強制GC可能引發(fā)卡頓) - 大對象用
Large Object Heap(避免Gen0碎片) - 值類型(struct)優(yōu)先(分配在棧,無GC壓力)
五、總結
GC如何改變編程?
| 傳統(tǒng)語言(C/C++) | C#/Java(帶GC) |
|---|---|
| 手動malloc/free | 自動創(chuàng)建回收 |
| 內存泄漏風險高 | 泄漏概率大幅降低 |
| 野指針引發(fā)崩潰 | 引用永遠指向有效對象 |
| 開發(fā)效率低 | 專注業(yè)務邏輯,生產力↑↑↑ |
GC哲學:把內存管理的臟活累活交給運行時,讓開發(fā)者更專注于創(chuàng)造價值!
附:GC觸發(fā)時機
- Gen0已滿(最常見)
- 系統(tǒng)物理內存不足
- 程序主動調用
GC.Collect()(不推薦) - AppDomain卸載或程序關閉
C# 的 GC 通過分代回收和標記 - 壓縮算法,自動管理內存,提高開發(fā)效率。理解其原理有助于寫出更高效的代碼,減少 GC 觸發(fā)頻率和 STW(Stop-The-World) 時間。
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
用C#+Selenium+ChromeDriver爬取網頁(模擬真實的用戶瀏覽行為)
這篇文章主要介紹了用C#+Selenium+ChromeDriver爬取網頁,模擬真實的用戶瀏覽行為,需要的小伙伴可以參考一下2022-01-01
C#中的Task.WhenAll和Task.WhenAny方法介紹
這篇文章介紹了C#中的Task.WhenAll和Task.WhenAny方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-04-04

