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

1. 暫停世界(Stop-The-World)
- GC發(fā)出指令:“所有線程立刻凍結(jié)!”
- 目的:防止標(biāo)記過(guò)程中對(duì)象狀態(tài)被修改,確保數(shù)據(jù)一致性。
2. 標(biāo)記階段(Mark):誰(shuí)還在用?
從根對(duì)象(Roots) 出發(fā):
- 靜態(tài)變量(墻上固定的掛鉤)
- 局部變量(操作臺(tái)上的臨時(shí)掛鉤)
- CPU寄存器中的引用(管理員手中的繩子)
深度追蹤:
- 沿著每根“繩子”找到對(duì)象,再檢查對(duì)象內(nèi)部的引用(如
person1.Dog),像波浪一樣擴(kuò)散標(biāo)記所有可達(dá)對(duì)象,并打上“存活”標(biāo)簽。
3. 清掃階段(Sweep):扔掉垃圾
- 遍歷整個(gè)堆內(nèi)存(倉(cāng)庫(kù))
- 所有未被標(biāo)記的對(duì)象 → 直接回收其內(nèi)存!
- (無(wú)任何引用指向 = 程序永遠(yuǎn)無(wú)法訪問(wèn) = 安全刪除)
4. 壓縮階段(Compact):整理碎片
// 壓縮前:內(nèi)存碎片化(空閑但分散) [對(duì)象A][空閑][對(duì)象B][空閑][對(duì)象C] // 壓縮后:對(duì)象緊密排列 [對(duì)象A][對(duì)象B][對(duì)象C][大塊連續(xù)空閑空間]
- 移動(dòng)存活對(duì)象到連續(xù)地址
- 更新所有引用(確保“繩子”指向新位置)
- 關(guān)鍵作用:避免內(nèi)存碎片,提升后續(xù)分配效率!
三、GC高效秘密武器:分代回收(Generations)
洞察規(guī)律:
“越新的對(duì)象,越容易變成垃圾;活得越久,越可能長(zhǎng)壽。”
.NET將堆內(nèi)存分為三代
| 代際 | 對(duì)象特點(diǎn) | GC檢查頻率 | 回收成本 |
|---|---|---|---|
| Gen0 | 新創(chuàng)建的小對(duì)象(如臨時(shí)變量) | 非常高 | 低 |
| Gen1 | 經(jīng)歷1次GC仍存活的對(duì)象 | 中等 | 中 |
| Gen2 | 長(zhǎng)期存活對(duì)象(如全局緩存) | 非常低 | 高 |
工作策略:
- 新對(duì)象默認(rèn)進(jìn)入Gen0
- Gen0滿 → 觸發(fā)GC(僅回收Gen0,速度極快)
- Gen0存活對(duì)象晉升Gen1
- Gen1滿 → 回收Gen0+Gen1
- Gen2滿 → 完全GC(回收所有代,性能影響大)
優(yōu)勢(shì):90%的垃圾在Gen0被回收,避免頻繁掃描老對(duì)象!
四、對(duì)開發(fā)者的關(guān)鍵啟示
1. 無(wú)需手動(dòng)釋放,但需“斷開引用”
讓對(duì)象變垃圾的正確方式:
// 方法1:引用置空
person1 = null;
// 方法2:超出作用域(局部變量自動(dòng)失效)
void CreateTempObject() {
var temp = new Object(); // 函數(shù)結(jié)束 → temp引用消失
}
// 方法3:重新賦值
person1 = new Person(); // 原對(duì)象失去引用2. 特殊資源需手動(dòng)釋放!
GC只回收內(nèi)存!文件句柄、數(shù)據(jù)庫(kù)連接等需通過(guò)IDisposable主動(dòng)釋放:
// 正確姿勢(shì):using自動(dòng)調(diào)用Dispose()
using (var file = File.Open("test.txt"))
{
// 操作文件...
} // 離開區(qū)域自動(dòng)關(guān)閉文件!
// 等價(jià)于手動(dòng)try-finally
try {
var file = File.Open("test.txt");
// ...
} finally {
file?.Dispose();
}3. 性能敏感場(chǎng)景優(yōu)化建議
- 避免高頻創(chuàng)建臨時(shí)對(duì)象(如循環(huán)內(nèi)
new) - 慎用
GC.Collect()(強(qiáng)制GC可能引發(fā)卡頓) - 大對(duì)象用
Large Object Heap(避免Gen0碎片) - 值類型(struct)優(yōu)先(分配在棧,無(wú)GC壓力)
五、總結(jié)
GC如何改變編程?
| 傳統(tǒng)語(yǔ)言(C/C++) | C#/Java(帶GC) |
|---|---|
| 手動(dòng)malloc/free | 自動(dòng)創(chuàng)建回收 |
| 內(nèi)存泄漏風(fēng)險(xiǎn)高 | 泄漏概率大幅降低 |
| 野指針引發(fā)崩潰 | 引用永遠(yuǎn)指向有效對(duì)象 |
| 開發(fā)效率低 | 專注業(yè)務(wù)邏輯,生產(chǎn)力↑↑↑ |
GC哲學(xué):把內(nèi)存管理的臟活累活交給運(yùn)行時(shí),讓開發(fā)者更專注于創(chuàng)造價(jià)值!
附:GC觸發(fā)時(shí)機(jī)
- Gen0已滿(最常見)
- 系統(tǒng)物理內(nèi)存不足
- 程序主動(dòng)調(diào)用
GC.Collect()(不推薦) - AppDomain卸載或程序關(guān)閉
C# 的 GC 通過(guò)分代回收和標(biāo)記 - 壓縮算法,自動(dòng)管理內(nèi)存,提高開發(fā)效率。理解其原理有助于寫出更高效的代碼,減少 GC 觸發(fā)頻率和 STW(Stop-The-World) 時(shí)間。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
c#獲取季度時(shí)間實(shí)例代碼(季度的第一天)
這篇文章主要介紹了c#獲取季度時(shí)間:季度的第一天、季度的最后一天等功能,大家參考使用吧2013-12-12
C# List集合中獲取重復(fù)值及集合運(yùn)算詳解
這篇文章主要介紹了C# List集合中獲取重復(fù)值及集合運(yùn)算詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12
C# 調(diào)用 JavaWebservice服務(wù)遇到的問(wèn)題匯總
本文給大家分享的是個(gè)人在使用C#調(diào)用 JavaWebservice服務(wù)遇到的幾個(gè)問(wèn)題的解決方法的匯總,給有類似需求的小伙伴們參考下吧。2016-01-01
UGUI實(shí)現(xiàn)ScrollView無(wú)限滾動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了UGUI實(shí)現(xiàn)ScrollView無(wú)限滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-02-02
漢字轉(zhuǎn)拼音縮寫示例代碼(Silverlight和.NET 將漢字轉(zhuǎn)換成為拼音)
本篇文章主要介紹了漢字轉(zhuǎn)拼音縮寫示例代碼(Silverlight和.NET 將漢字轉(zhuǎn)換成為拼音) 需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2014-01-01
淺談c#.net中巧用ToString()將日期轉(zhuǎn)成想要的格式
有時(shí)候我們要對(duì)時(shí)間進(jìn)行轉(zhuǎn)換,達(dá)到不同的顯示效果,更多的該怎么辦呢?2013-03-03
C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件
這篇文章介紹了C#在復(fù)雜多線程環(huán)境下使用讀寫鎖同步寫入文件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04

