CLR中的内存管理

在C++中,令程序员最头疼的是对内存的分配和管理。在.net下,事情容易多了。.net引用了垃圾回收(GC)功能,它替代了程序员对于清除无用对象的工作。虽然在大多数情况下,内存的回收我们不用再去理会,但如果能够在程序中适时地添加一些内存管理的工作,可以使程序更加的优化。


由于CLR(公共语言运行时)可以知道在系统中的所有对象引用,因此在运行时,GC可以获取对象是否被引用的信息。如果一个对象不再被引用,则通过GC进行自动回收。


不过GC回收的条件是,当特定资源不够用时才执行。如果我们希望自己控制,也可以显示地指示GC工作。方法是:


System.GC.Collect();


GC在进行回收时,先会识别对象是否被引用,并标记出对象的特征。只有不被引用的对象才被回收。为避免堆碎片,GC在回收了对象后,会重新分配内存,并对未被回收的对象进行重定位。这必然导致GC在回收时会导致系统运行性能的降低。


适时的进行人工干预内存分配,是比较好的选择。我们知道在C++中,对于创建的类中,有相对应的析构函数进行内存的删除。在C#中,也可以采用同样的方式。当实例化一个类对象后,删除它,则自动调用其析构函数。CLR提供了对象终结(object finalization)的机制,引入了Finalize方法。不过在C#中,不能直接实现Finalize方法,而是在析构函数中调用基类的Finalize()方法。

GC的回收机制是异步操作,我们可以使用CLR提供的Dispose()方法实现对每一个对象的删除操作。Dispose()方法由IDiposable接口提供。因此对于将要实例化的类对象,实现Dispose操作,必须使类实现该接口,并提供Dispose()方法。

public class Garbage:IDisposable//实现该接口
{
   public void Dispose()//提供Dispose()方法;
   {
       GC.SuppressFinalize(this);//回收该对象;
   }

   ~Garbage()//析构函数;
   {
       Dispose();
   }
}

不过更好的方案是使用using语句。将对象的实例放到using中,一旦using结束,系统会自动清楚该对象。

using (Garbage g = new Garbage())
{
    //执行操作;
}

不过要注意的是在using语句中实例的对象,其类也必须要实现IDisposable接口和Dispose()方法。
另外,由于IComponent扩展了IDisposable,因此IComponent类型始终是IDisposable类型。所以我们开发的组件类型可以用在using中,或者使用Dispose()方法。所以,系统提供的组件如DataSet,DataTable等的实例也可以实现这种方式来清除对象。

参考MSDN和.Net本质论

posted on 2004-04-21 09:26 张逸 阅读(1442) 评论(8)  编辑 收藏 所属分类: .NET FrameWork

评论

#1楼  2004-08-12 11:54 笨笨      

不错~~   回复  引用  查看    

#2楼  2005-03-14 15:11 寒枫天伤 [未注册用户]

“GC.SuppressFinalize(this);//回收该对象;”

这条语句并不是回收对象吧?应该是阻止垃圾回收器再次回收此对象,

析构函数是给GC用的,GC.SuppressFinalize(this)是为了告诉GC:“我已经回收过了,不用再回收我了”。

实际上,如果调用了Dispose,你上面的代码中析构函数中的代码就不会执行。释放资源的任务就到了Dispose中了。

个人愚见,没有深入研究,仅供参考。   回复  引用    

#3楼  2005-03-27 10:07 ironworm [未注册用户]

.netSDK的说明
对于您的应用程序创建的大多数对象,可以依靠 .NET Framework 的垃圾回收器隐式地执行所有必要的内存管理任务。但是,在您创建封装非托管资源的对象时,当您在应用程序中使用完这些非托管资源之后,您必须显式地释放它们。最常见的一类非托管资源就是包装操作系统资源的对象,例如文件、窗口或网络连接。虽然垃圾回收器可以跟踪封装非托管资源的对象的生存期,但它不了解具体如何清理这些资源。对于这些类型的对象,.NET Framework 提供 Object.Finalize 方法,它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。默认情况下,Finalize 方法不执行任何操作。如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写 Finalize 方法。当使用 C# 和 C++ 的托管扩展以外的编程语言进行开发时,您可以实现 Finalize 方法。C# 和托管扩展提供析构函数作为编写终止代码的简化机制。析构函数自动生成 Finalize 方法和对基类的 Finalize 方法的调用。在 C# 和托管扩展编程语言中,您必须为终止代码使用析构函数语法。

垃圾回收器使用名为“终止队列”的内部结构跟踪具有 Finalize 方法的对象。每次您的应用程序创建具有 Finalize 方法的对象时,垃圾回收器都在终止队列中放置一个指向该对象的项。托管堆中所有需要在垃圾回收器回收其内存之前调用它们的终止代码的对象都在终止队列中含有项。

实现 Finalize 方法或析构函数对性能可能会有负面影响,因此应避免不必要地使用它们。用 Finalize 方法回收对象使用的内存需要至少两次垃圾回收。当垃圾回收器执行回收时,它只回收没有终结器的不可访问对象的内存。这时,它不能回收具有终结器的不可访问对象。它改为将这些对象的项从终止队列中移除并将它们放置在标为准备终止的对象列表中。该列表中的项指向托管堆中准备被调用其终止代码的对象。垃圾回收器为此列表中的对象调用 Finalize 方法,然后,将这些项从列表中移除。后来的垃圾回收将确定终止的对象确实是垃圾,因为标为准备终止对象的列表中的项不再指向它们。在后来的垃圾回收中,实际上回收了对象的内存。
  回复  引用    

#4楼  2005-05-10 18:04 ZendyHu      

关于垃圾回收机制中,作者可能还一些误解:

关于Finalize 及 Dispose() Dispose(bool disposing)的三者关系及编码范例 可见我的文章:http://www.cnblogs.com/caomao/archive/2005/05/10/152505.html

  回复  引用  查看    

#5楼  2005-05-11 09:34 wayfarer      

写了这篇文章后,一直没有看到各位的评论.确实自己在内存管理方面的理解还是有偏差的.谢谢寒枫天伤,ironworm,ZendyHu三位.受教了.

btw,ZendyHu的那篇文章值得一看,把Dispose阐述得很清楚,同时从中我们也可以在自己的设计中,借鉴这种好的模式.

这种模式很简单,不过就是方法的重载,并对方法作不同的修饰,以限制访问者的权限而已,但却很有用.   回复  引用  查看    

#6楼  2005-05-11 16:54 ZendyHu      

希望我们以后相互多多学习   回复  引用  查看    

#7楼  2006-03-20 10:16 Jiang Jin Nan      

GC.SuppressFinalize(this) 是阻止GC调用该对象的Finalize方法
  回复  引用  查看    

#8楼  2008-04-23 18:36 笨→鸟(Bird)      

好象现在都using用得比较多。   回复  引用  查看    


标题  
姓名  
主页
Email (只有博主才能看到) 
验证码 *  看不清,换一张 [登录][注册]
内容(请不要发表任何与政治相关的内容)  
  登录  使用高级评论  新用户注册  返回页首  恢复上次提交      


相关链接:
 



导航

公告

logo.gif
我的著作与译作

《软件设计精要与模式》

《WCF服务编程》

MVP_Horizontal_BlueOnly.png

From 03-03-2006
Counter: site stats

与我联系

搜索

 

常用链接

我参加的小组

我参与的团队

随笔分类(243)

随笔档案(235)

最新随笔

积分与排名

最新评论

阅读排行榜

评论排行榜