C# 内存管理核心:内存基础、GC、IDisposable、using 模式
<h2>一、内存基础:栈 vs 堆</h2><div> </div>
<div>C# 把内存分成两块核心区域,分配规则完全不同,这是理解 GC 的前提。</div>
<div> </div>
<h3>1. 栈内存 (Stack)</h3>
<div> </div>
<ul>
<li>存放内容:值类型(int、bool、struct)、引用类型变量的引用地址</li>
<li>特点:
<ul>
<li>自动分配、自动释放(方法执行完立刻释放)</li>
<li>速度极快,无需 GC 管理</li>
<li>大小固定,空间小</li>
</ul>
<div> </div>
</li>
<li>生命周期:跟随方法 / 代码块,执行结束立即回收</li>
</ul>
<div> </div>
<h3>2. 托管堆 (Heap)</h3>
<div> </div>
<ul>
<li>存放内容:引用类型(string、class、数组、委托)</li>
<li>特点:
<ul>
<li>动态分配,空间大</li>
<li>手动不释放,由 GC(垃圾回收器)自动管理</li>
</ul>
<div> </div>
</li>
<li>生命周期:没有引用指向它时,GC 才会回收</li>
</ul>
<div> </div>
<h3>总结</h3>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>int a = 10; // 栈:方法结束自动没了
string s = "abc";// 栈存引用地址,堆存真实数据:GC 负责回收
</code></pre>
</div>
<div> </div>
</div>
</div>
<div> </div>
<hr>
<div> </div>
<h2>二、GC 常识:垃圾回收机制</h2>
<div> </div>
<div>GC = Garbage Collector,C# 的自动内存管家,专门清理托管堆上没用的对象。</div>
<div> </div>
<h3>1. GC 做什么?</h3>
<div> </div>
<ul>
<li>找到堆上没有任何引用的无用对象</li>
<li>释放它们的内存</li>
<li>压缩内存(让存活对象紧凑排列,减少内存碎片)</li>
</ul>
<div> </div>
<h3>2. GC 什么时候工作?</h3>
<div> </div>
<ul>
<li>新对象分配,堆空间不足时(主动触发)</li>
<li>系统内存紧张时</li>
<li>手动调用 <code>GC.Collect()</code>(不推荐,会影响性能)</li>
</ul>
<div> </div>
<h3>3. GC 关键特点</h3>
<div> </div>
<ol>
<li>只清理托管资源
<div> </div>
托管资源 = 堆上的对象(string、class 等)</li>
<li>不清理非托管资源
<div> </div>
非托管资源 = 文件句柄、数据库连接、网络套接字、图片流、窗口句柄
<div> </div>
→ 这些必须手动释放,GC 管不了!</li>
<li>GC 回收是异步、不确定时间的
<div> </div>
你无法控制它什么时候执行,所以非托管资源不能等 GC。</li>
</ol>
<div> </div>
<hr>
<div> </div>
<h2>三、IDisposable 接口:手动释放非托管资源</h2>
<div> </div>
<h3>1. 为什么需要它?</h3>
<div> </div>
<div>GC 不管非托管资源,如果不手动释放:</div>
<div> </div>
<ul>
<li>文件被占用无法删除</li>
<li>数据库连接耗尽</li>
<li>内存泄漏</li>
<li>程序卡顿、崩溃</li>
</ul>
<div> </div>
<div>解决方案:让类实现 <code>IDisposable</code></div>
<div> </div>
<h3>2. IDisposable 只有一个方法</h3>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>public interface IDisposable
{
void Dispose();
}
</code></pre>
</div>
<div> </div>
</div>
</div>
<h3>3. 实现模板</h3>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>public class MyResource : IDisposable
{
// 标记是否已经释放
private bool _disposed = false;
// 公共方法:外部调用释放
public void Dispose()
{
Dispose(true);
// 告诉 GC:不用调用析构函数了,我已经手动释放完了
GC.SuppressFinalize(this);
}
// 核心释放逻辑
protected virtual void Dispose(bool disposing)
{
if (_disposed) return;
if (disposing)
{
// 释放 托管资源
}
// 释放 非托管资源(文件、数据库连接、流等)
// 例:file.Close();dbConnection.Close();
_disposed = true;
}
// 析构函数:防止用户忘记调用 Dispose,GC 时兜底
~MyResource()
{
Dispose(false);
}
}
</code></pre>
</div>
<div> </div>
</div>
</div>
<div> </div>
<hr>
<div> </div>
<h2>四、using 模式:优雅的自动释放</h2>
<div> </div>
<div><code>using</code> 是 C# 给 <code>IDisposable</code> 准备的语法糖,自动调用 Dispose (),无论代码是否正常执行、是否报错。</div>
<div> </div>
<h3>1. 核心作用</h3>
<div> </div>
<ul>
<li>包裹实现了 IDisposable 的对象</li>
<li>代码块结束 → 自动释放资源</li>
<li>异常也能保证释放,绝对安全</li>
</ul>
<div> </div>
<h3>2. 两种写法</h3>
<div> </div>
<h4>写法 1:推荐(简洁)</h4>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>using (var stream = new FileStream("test.txt", FileMode.Create))
{
// 使用流
stream.WriteByte(1);
}
// 离开大括号:自动调用 stream.Dispose()
</code></pre>
</div>
<div> </div>
</div>
</div>
<h4>写法 2:多个资源(C# 8.0+)</h4>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>using var stream = new FileStream("test.txt", FileMode.Create);
using var reader = new StreamReader(stream);
// 方法结束时自动释放
</code></pre>
</div>
<div> </div>
</div>
</div>
<h3>3. 本质原理</h3>
<div> </div>
<div><code>using</code> 等价于 <code>try-finally</code>:</div>
<div> </div>
<div>
<div dir="ltr">
<div>
<pre><code>FileStream stream = null;
try
{
stream = new FileStream("test.txt", FileMode.Create);
}
finally
{
stream?.Dispose();
}
</code></pre>
</div>
<div> </div>
</div>
</div>
<div> </div>
<hr>
<div> </div>
<h2>五、四者关系总结</h2>
<div> </div>
<ol>
<li>内存基础:栈自动释放,堆靠 GC</li>
<li>GC:只回收托管堆,不管非托管资源</li>
<li>IDisposable:定义手动释放非托管资源的规范</li>
<li>using:简化 <code>IDisposable</code>,自动调用 <code>Dispose()</code>,安全不遗漏</li>
</ol>
<div> </div>
<hr>
<div> </div>
<h2>六、开发实践</h2>
<div> </div>
<ol>
<li>只要用到文件、数据库、流、Socket、图片,一律用 <code>using</code></li>
<li>自己写的类包含非托管资源 → 实现 <code>IDisposable</code></li>
<li>不要手动调用 GC.Collect ()</li>
<li>using 优先于手动 Dispose ()</li>
</ol>
<div> </div>
<hr>
<div> </div>
<h3>总结</h3>
<div> </div>
<ol>
<li>栈自动释放,堆由 GC 管理,GC 不处理非托管资源</li>
<li>IDisposable 是手动释放非托管资源的标准接口</li>
<li>using 是自动调用 Dispose 的语法糖,安全、简洁、你就用吧</li>
<li>文件 / 流 / 数据库连接 → 全部套 <code>using</code></li>
</ol><br><br>
来源:https://www.cnblogs.com/chuansheng/p/19909164
頁:
[1]