1、 .NET Resource Management Bill Wagner Effective C#: 50 Specific Ways to Improve Your C#, Chapter 2, .NET Resource Management, Bill Wagner, Addison Wesley Professional, 2004, 77115 .NET 资源管理 比尔 瓦格拉 Effective C# 中文版改善 C#程序的 50 种方法 ,第二章, .NET 资源管理,比尔 瓦格拉, 2004, 77115 一个简单的事实: .Net 应用程序是在一个托管的环境里运行的,这个环
2、境和不同的设计器有很大的冲突,这就才有了 Effective C#。极大限度上的讨论这个环境的好处,须要把你对本地化环境的想法改变为 .Net CLR。也就意味着要明 1 白 .Net 的垃圾回收器。在你明白这一章里所推荐的内容时,有必要对 .Net 的内存管理环境有个大概的了解。那我们就开始大概的了解一下吧。 垃圾回收器 (GC)为你控制托管内存。不像本地运行环境,你不用负责对内存泄漏,不定指针,未初始化指针,或者一个其它内存管理的服务问题。但 垃圾回收器前不是一个神话:你一样要自己清理。你要对非托管资源负责,例如文件句柄,数据链接, GDI+对象, COM 对象,以及其它一些系统对象。 这
3、有一个好消息:因为 GC 管理内存,明确的设计风格可以更容易的实现。循环引用,不管是简单关系还是复杂的网页对象,都非常容易。 GC 的标记以及严谨的高效算法可以检测到这些关系,并且完全的删除不可达的网页对象。 GC 是通过对从应用程序的根对象开始,通过树形结构的 “ 漫游 ” 来断定一个对象是否可达的,而不是强迫每个对象都保持一些引用跟踪, COM 就是这样的。 DataSet 就是一个很好的例 子,展示了这样的算法是如何简化并决定对象的所属关系的。 DataSet是一个 DataTable 的集合,而每一个 DataTable 又是 DataRow 的集合,每一个DataRow 又是 Dat
4、aItem 的集合, DataColum 定义了这些类型的关系。这里就有一些从 DataItem 到它的列的引用。而同时, DataTime 也同样有一个引用到它的容器上,也就是 DataRow。 DataRow 包含引用到 DataTable,最后每个对象都包含一个引用到 DataSet。 如果这还不够复杂,那可以创建一个 DataView,它提供对经 过过滤后的数据表的顺序访问。这些都是由 DataViewManager 管理的。所有这些贯穿网页的引用构成了 DataSet。释放内存是 GC 的责任。因为 .Net 框架的设计者让你不必释放这些对象,这些复杂的网页对象引用不会造成问题。没有
5、必须关心这些网页对象的合适的释放顺序,这是 GC 的工作。 GC 的设计结构可以简化这些问题,它可以识别这些网页对象就是垃圾。在应用程序结束了对 DataSet 的引用后,没有人可以引用到它的子对象了 (译注:就是 DataSet 里的对象再也引用不到了 )。因此,网页里还有没有对象循环引用 DataSet, DataTables 已经一点也不重要了,因为这些对象在应用程序都已经不能被访问到了,它们是垃圾了 。 垃圾回收器在它独立的线程上运行,用来从你的程序里移除不使用的内存。而且在每次运行时,它还会压缩托管堆。压缩堆就是把托管堆中活动的对象移到一起,这样就可以空出连续的内存。图 2.1 展示
6、了两个没有进行垃圾回收时的内存快照。所有的空闲内存会在垃圾回收进行后连续起来 。 2 图 2.1 垃圾回收器不仅仅是移动不使用的内存,还移除动其它的对象,从而压缩使用的内存,让出最多的空闲内存 。 正如你刚开始了解的,垃圾回收器的全 部责任就是内存管理。但,所有的系统资源都是你自己负责的。你可以通过给自己的类型定义一个析构函数,来保证释放一些系统资源。析构函数是在垃圾回收器把对象从内存移除前,由系统调用的。你可以,也必须这样来释放任何你所占用的非托管资源。对象的析构函数有时是在对象成为垃圾之后调用的,但是在内存归还之前。这个非确定的析构函数意味着在你无法控制对象析构与停止使用之间的关系 (译注
7、:对象的析构与对象的无法引用是两个完全不同的概念。关于 GC,本人推荐读者参考一下 Jeffrey 的.Net 框架程序设计 (修订版 )中讨论的垃圾回收器 )。对 C+来说这是个重大的改变,并且这在设计上有一个重大的分歧。有经验的 C+程序员写的类总在构造函数内申请内存并且在析构函数中释放它们 : / 好的 C+, 坏的 C#: class CriticalSection public: / 构造系统需要的资源 CriticalSection( ) EnterCriticalSection( ); / 销毁资源 CriticalSection( ) ExitCriticalSection( ); ; / 使用 : void Func( )