程序的资源分为托管资源与非托管资源,CLR直接管理的资源就是托管资源,还有一类非托管资源如IO、Socket、AplicationContext、Regex、Stream流、数据库操作等等,这些直接由系统管理占用内存。在垃圾回收的时候,虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。 上一篇文章说了托管资源与垃圾回收,下面说说非托管资源垃圾回收:
我们知道回收一个资源需要调用它的finalize方法,但是finalize方法不是一个公用的方法,我们并不知道怎么去调用它。.NET提供的 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。 默认情况下,Finalize 方法不执行任何操作。 如果您要让垃圾回收器在回收对象的内存之前对非托管资源执行清理操作,您必须在类中重写 Finalize 方法。(有人可能要问finalize方法和析构函数是一个吗, 其实析构函数是隐式的对对象的基类调用了Object.Finalize方法)
来说说IDisposable接口,要提供显示释放或者关闭对象的能力,一个类型通常要实现一种被称为Dispose的模式,Dispose模式定义了开发人员在实现类型的显式资源清理功能时所需要遵循的一些约定,如果一个类型实现了Dispose模式,使用该类型的开发者就知道当对象不再被使用的时候如何显式的释放掉它所占用的资源。
下面是一个简单的例子:
<span style="font-family:Arial;font-size:12px;">public class Test:IDisposable
{
private Brush brush;
private bool isDisposed = false;
public Test(Brush br)
{
this.brush = br;
}
~Test()
{
Dispose(false); //释放非托管资源
}
public void Dispose()
{
//因为对象的资源被显式的释放,所以这里阻止垃圾回收器回收
GC.SuppressFinalize(this);
Dispose(true);
}
public void Close()
{
Dispose();
}
private void Dispose(bool disposing)
{
lock (this)
{
if(disposing)
{
//这里释放托管资源
}
if(!isDisposed)
{
//这里释放非托管资源
}
isDisposed = true;
}
}
}</span>
上面的例子展示了如何手动清理内存,有任何建议请留言。
还有一种比较常用的释放非托管资源的方法 using 语句,using语句只能用于那些实现了IDisposable接口的类型(个人感觉using非常简洁好用)
<span style="font-family:Arial;font-size:12px;"><span style="white-space:pre"> </span> using(FileStream fs = new FileStream("Test.txt",FileMode.Create))
{
//FileStream 只在括号内有效
}</span>
再说一个弱引用,个人感觉弱引用在程序中也比较实用
什么时候使用:一些数据,它们很容易创建但是却需要大量内存。比如,我们想要知道硬盘中所有的目录和文件,用一个树来表示,问题在于这个树非常庞大需要内多内存。如果用户转而访问程序其他部分,这个树可能就不那么必要,但是却占用很多内存。我们可能放弃这个树的根的引用,如果用户再需要就重新创建。这个时候,弱引用就派上用场了。
例子:
<span style="font-family:Arial;font-size:12px;">private void SomeMethod()
{
Object o = new Object();
WeakReference wr = new WeakReference(o); //这是个短弱引用(不做介绍了)
o = null; //移除对象的强引用
o = wr.Target;
if (o == null)
{
//出现过垃圾回收,对象的内存已经被回收
}
else
{
//未出现垃圾回收,我们可以使用变量o来访问对象
}
}</span>
就写到这里吧,读者若有高见可以留言讨论