深入.NET托管堆(managed heap)(下)

来源:sam1111 的 Blog  作者:csdn
摘要:在这里,对象可以通过两种方式被清除。第一种方式是通过IDisposable接口的Dispose方法。此方法在对象显式地结束时被客户代码调用,它调用InternalDispose(true)。在这种情况下所有的对象都被清除了。如果析构函数被调用,那么Intern…

在这里,对象可以通过两种方式被清除。第一种方式是通过IDisposable接口的Dispose方法。此方法在对象显式地结束时被客户代码调用,它调用InternalDispose(true)。在这种情况下所有的对象都被清除了。如果析构函数被调用,那么InternalDispose(false)被调用,此时只有外部资源会被释放。如果我们已经执行了终止操作,那么我们自己的对象有可能已经被释放了,此后对它们的引用有可能引起异常。

对GC.SuppressFinalize的调用会阻止垃圾收集器将对象放入终止队列中。这样做可以降低在一次GC过程中由于整理对象而引起的内存消耗,并且由于终止操作不会被调用,从而使性能得到提高。

对C#的优化

因此使用IDisposable.Dispose()来释放资源是个很好的方式,它不但可以减少一些在托管堆上进行操作的内存需求,而且能够减少必须执行终止操作的对象的数量。但是它使用起来比较麻烦,尤其是有多个临时对象被创建的时候更是如此。为了能够从IDisposable接口受益,C#客户程序应该书写象下面这样的代码:

OverdueBookLocator bookLocator = null;

try

{

bookLocator = new OverdueBookLocator();

// Use bookLocator here

Book book = bookLocator.Find("Eiffel, the Language");

 ......

}

finally

{

if(bookLocator != null)

{

IDisposable disp = bookLocator as IDisposable;

disp.Dispose();

}

}

finally中的代码被用来在有异常发生时作适当的清理工作。为了C#客户程序能够简单有效地使用Dispose模式,Beta2引入了using表达式。Using表达式允许你简化你的代码,因此上面的代码可以写成:

using(bookLocator = new OverdueBookLocator())

{

// Use bookLocator here

Book book = bookLocator.Find("Eiffel, the Language");

}

无论何时分配具有明确定义的生存期的类型时,你都应该使用using表达式。它能保证对IDisposable接口的适当调用,即使是在有异常发生的时候。

使用System.GC类

System.GC类用来访问被.NET framework暴露出来的垃圾回收机制。这个类包含以下一些有用的方法:

●   GC.SuppressFinalize 这个方法在前面已经描述过了,它能够抑制终止操作。如果你已经将属于一个对象的外部资源释放了,调用这个方法来抑制此对象的终止操作的执行。

●   GC.Collect 具有两个版本。不带参数的版本在托管堆的所有generation上执行回收动作。另一个版本带有一个整型参数,此参数指明所要进行回收操作的generation。你将很少调用这个方法,因为垃圾收集器在需要的时候会自动调用它。

●   GC.GetGeneration 返回作为参数传入的对象所在的generation。这个方法在由于性能的原因而进行的调试和跟踪中很有作用,但是在大部分应用中作用有限。

●   GC.GetTotalMemory 返回堆中已经被分配的内存总量。由于托管堆的工作方式,这个数字并不精确,但是如果你以true作为参数的话,还是会得到一个比较接近的近似值。这个方法在计算之前会先执行一遍回收操作。

下面是使用这些方法的一个例子:

/// <summary>

/// Displays current GC information

/// </summary>

/// <param name="generation">The generation to collect</param>

/// <param name="waitForGC">Run GC before calculating usage?</param>

public void CollectAndAudit(int generation, bool waitForGC)

{

int myGeneration = GC.GetGeneration(this);

long totalMemory = GC.GetTotalMemory(waitForGC);

Console.WriteLine("I am in generation {0}.", myGeneration);

Console.WriteLine("Memory before collection {0}.", totalMemory);

GC.Collect(generation);

Console.WriteLine("Memory after collection {0}.", totalMemory);

}

关于本文作者

Mickey Williams是Codev Technologies的创始人之一。Codev Technologies是一家从事位Windows程序开发者提供咨询和工具的机构。他同时也是.NET Experts (http://www.codeguru.com/columns/DotNet/www.dotnetexperts.com)的主要成员,他在此讲授.NET Framework的课程。他时常在美国和欧洲的一些研讨会上发表演讲,并且已经写了八本有关Windows程序设计方面的著作。他目前正被微软出版社邀请写作“Microsoft Visual C#”。你可以在mw@codevtech.com找到他。

作者Blog:http://blog.csdn.net/sam1111/

【相关文章】好搜一下
使用Visual Studio 2010空白解决方案的三个理由

使用Visual Studio 2010空白

在Visual Studio 2010(包括以前的版本中)都提供了很多现成的解决…