C# GC回收的方法實現(xiàn)
介紹 C# 中的 垃圾回收(Garbage Collection, GC) 機制。
?? 一、什么是 GC?
GC(Garbage Collector,垃圾回收器) 是 .NET 運行時(CLR)自動管理內(nèi)存的核心組件。
它的作用是:
自動找出不再被使用的對象(“垃圾”),并釋放它們占用的內(nèi)存,防止內(nèi)存泄漏。
你不需要像 C/C++ 那樣手動 delete 或 free,C# 的 GC 會幫你搞定!
?? 二、GC 管理的是哪部分內(nèi)存?
在 C# 中,內(nèi)存主要分為兩塊:
| 內(nèi)存區(qū)域 | 存放內(nèi)容 | 是否由 GC 管理 |
|---|---|---|
| 托管堆(Managed Heap) | 引用類型對象(如 class 實例) | ? 是 |
| 棧(Stack) | 值類型(如 int, struct)、方法局部變量、引用類型的引用(指針) | ? 否(隨方法結(jié)束自動釋放) |
?? 注意:string、數(shù)組、自定義 class 都分配在托管堆上,由 GC 負責回收。
?? 三、GC 什么時候觸發(fā)?
GC 不是實時運行的,而是在滿足以下條件之一時自動觸發(fā):
- 托管堆內(nèi)存不足(分配新對象時發(fā)現(xiàn)空間不夠)
- 系統(tǒng)內(nèi)存壓力大(Windows 通知 .NET 內(nèi)存緊張)
- 手動調(diào)用 GC.Collect()(不推薦!除非特殊場景)
?? 開發(fā)者通常無法精確控制 GC 何時發(fā)生,這是設(shè)計上的有意為之——讓開發(fā)者專注業(yè)務(wù)邏輯。
??? 四、GC 如何判斷一個對象是“垃圾”?
核心原則:如果一個對象無法從“根(Root)”訪問到,它就是垃圾。
什么是“根(Root)”?
- 全局/靜態(tài)變量
- 方法中的局部變量(包括參數(shù))
- CPU 寄存器中的引用
- 本地方法(Native code)持有的引用
示例:
void MyMethod()
{
var person = new Person(); // person 是局部變量 → 根
person.Name = "Alice";
} // 方法結(jié)束,person 超出作用域 → 不再是根
→ 此時 Person 對象不可達,下次 GC 時會被回收。
?? 五、GC 的核心機制:分代回收(Generational GC)
.NET 的 GC 采用 “分代回收” 策略,把對象按“年齡”分成三代:
| 代(Generation) | 特點 | 回收頻率 |
|---|---|---|
| Gen 0 | 新創(chuàng)建的對象 | ?? 最頻繁(毫秒級) |
| Gen 1 | 活過一次 Gen 0 回收的對象 | 中等 |
| Gen 2 | 老對象(活過 Gen 1) | ?? 最少(可能幾秒甚至幾分鐘一次) |
為什么分代?
經(jīng)驗規(guī)律:大多數(shù)對象“朝生暮死”(比如臨時變量)。
所以優(yōu)先快速回收 Gen 0,避免全堆掃描,提升性能。
回收過程簡述:
- GC 暫停所有線程(“Stop-The-World”)
- 從“根”出發(fā),標記所有可達對象
- 清除未標記對象(垃圾)
- 壓縮內(nèi)存:把存活對象往堆的一端移動,消除碎片
- 晉升:Gen 0 存活對象 → Gen 1;Gen 1 存活 → Gen 2
?? Gen 2 回收也叫 Full GC,開銷最大,應(yīng)盡量避免頻繁發(fā)生。
?? 六、如何查看對象在哪一代?
可以使用 GC.GetGeneration(object):
var obj = new object(); Console.WriteLine(GC.GetGeneration(obj)); // 輸出 0 GC.Collect(); // 強制回收 Gen 0 Console.WriteLine(GC.GetGeneration(obj)); // 如果 obj 還被引用,輸出 1
??? 七、特殊對象:需要“清理”的資源
GC 只負責內(nèi)存回收,但有些對象持有非托管資源(如文件句柄、數(shù)據(jù)庫連接、網(wǎng)絡(luò) socket),這些資源不會自動釋放!
解決方案:實現(xiàn)IDisposable+Dispose模式
public class MyFile : IDisposable
{
private FileStream _file;
public MyFile(string path)
{
_file = File.OpenRead(path);
}
public void Dispose()
{
_file?.Dispose(); // 立即釋放非托管資源
GC.SuppressFinalize(this); // 告訴 GC:不用調(diào)用析構(gòu)函數(shù)了
}
~MyFile() // 析構(gòu)函數(shù)(Finalizer)— 最后的保險
{
Dispose();
}
}
// 使用方式(推薦 using)
using (var file = new MyFile("data.txt"))
{
// 使用文件
} // 自動調(diào)用 Dispose()
? 最佳實踐:對持有非托管資源的類,務(wù)必實現(xiàn) IDisposable,并用 using 語句確保及時釋放。
?? 八、GC 對性能的影響 & 優(yōu)化建議
可能的問題:
- Stop-The-World:GC 期間所有線程暫停,可能導(dǎo)致 UI 卡頓
- 頻繁分配/回收:大量臨時對象 → 頻繁 Gen 0 GC → CPU 浪費
- 大對象堆(LOH):≥85,000 字節(jié)的對象分配在 LOH,不會壓縮,易產(chǎn)生內(nèi)存碎片
優(yōu)化建議:
| 場景 | 建議 |
|---|---|
| 頻繁創(chuàng)建小對象 | ?? 重用對象(對象池 ObjectPool<T>) |
| 大數(shù)組/緩沖區(qū) | ?? 使用 ArrayPool<T>.Shared |
| 長時間持有對象 | ?? 避免無意中延長對象生命周期(如事件訂閱未取消) |
| 高性能場景 | ?? 減少分配(如用 Span<T>、stackalloc) |
| 監(jiān)控 GC | ?? 使用 PerfView、dotMemory 或 GC.CollectionCount |
// 查看各代 GC 次數(shù)
Console.WriteLine($"Gen 0: {GC.CollectionCount(0)}");
Console.WriteLine($"Gen 1: {GC.CollectionCount(1)}");
Console.WriteLine($"Gen 2: {GC.CollectionCount(2)}");
?? 九、GC vs 手動內(nèi)存管理(C++)
| 特性 | C# GC | C++ 手動管理 |
|---|---|---|
| 內(nèi)存安全 | ? 不會野指針、重復(fù)釋放 | ? 容易出錯 |
| 開發(fā)效率 | ? 高 | ? 低 |
| 性能可控性 | ? 較低(GC 不可預(yù)測) | ? 高 |
| 內(nèi)存碎片 | ? GC 會壓縮堆 | ? 需手動管理 |
?? C# 的設(shè)計理念:用少量性能代價,換取極高的開發(fā)安全性和效率。
? 總結(jié):關(guān)鍵要點
- GC 自動回收托管堆上的無用對象,開發(fā)者無需手動釋放。
- 分代回收(Gen 0/1/2) 是核心優(yōu)化策略,基于“多數(shù)對象短命”假設(shè)。
- GC 不處理非托管資源 → 必須用 IDisposable + using。
- 避免頻繁分配臨時對象,尤其在循環(huán)或高頻方法中。
- 不要隨意調(diào)用 GC.Collect() —— 通常適得其反。
- 大對象(≥85KB)進入 LOH,不壓縮,需特別注意。
如果你正在開發(fā)高性能應(yīng)用(如游戲、實時系統(tǒng)),理解 GC 行為至關(guān)重要;如果是普通業(yè)務(wù)系統(tǒng),只需記?。?strong>少 new 臨時對象,及時 Dispose 資源,就能避開 90% 的問題。
到此這篇關(guān)于C# GC回收的方法實現(xiàn)的文章就介紹到這了,更多相關(guān)C# GC回收內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
WinForm實現(xiàn)窗體最大化并遮蓋任務(wù)欄的方法
這篇文章主要介紹了WinForm實現(xiàn)窗體最大化并遮蓋任務(wù)欄的方法,涉及C#實現(xiàn)WinForm窗體全屏顯示的實現(xiàn)及調(diào)用技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-08-08
C#的靜態(tài)工廠方法與構(gòu)造函數(shù)相比有哪些優(yōu)缺點
這篇文章主要介紹了C#的靜態(tài)工廠方法與構(gòu)造函數(shù)對比的優(yōu)缺點,文中示例代碼非常詳細,幫助大家更好的理解和學習,感興趣的朋友可以了解下2020-07-07
C# 實現(xiàn)dataGridView選中一行右鍵出現(xiàn)菜單的示例代碼

