终于开始动手写这篇文章了,有个网友催了我好几次,今天终于可以静下心来完成它。
便于对文章的开展,需要先明确两个概念。
第一个就是很多人用.Net写程序,会谈到托管这个概念。那么.Net所指的资源托管到底是什么意思,是相对于所有资源,还是只限于某一方面资源?很多人对此不是很了解,其实.Net所指的托管只是针对内存这一个方面,并不是对于所有的资源;因此对于Stream,数据库的连接,GDI+的相关对象,还有Com对象等等,这些资源并不是受到.Net管理而统称为非托管资源。而对于内存的释放和回收,系统提供了GC-Garbage Collector,而至于其他资源则需要手动进行释放。
那么第二个概念就是什么是垃圾,通过我以前的文章,会了解到.Net类型分为两大类,一个就是值类型,另一个就是引用类型。前者是分配在栈上,并不需要GC回收;后者是分配在堆上,因此它的内存释放和回收需要通过GC来完成。GC的全称为“Garbage Collector”,顾名思义就是垃圾回收器,那么只有被称为垃圾的对象才能被GC回收。也就是说,一个引用类型对象所占用的内存需要被GC回收,需要先成为垃圾。那么.Net如何判定一个引用类型对象是垃圾呢,.Net的判断很简单,只要判定此对象或者其包含的子对象没有任何引用是有效的,那么系统就认为它是垃圾。
明确了这两个基本概念,接下来说说GC的运作方式以及其的功能。内存的释放和回收需要伴随着程序的运行,因此系统为GC安排了独立的线程。那么GC的工作大致是,查询内存中对象是否成为垃圾,然后对垃圾进行释放和回收。那么对于GC对于内存回收采取了一定的优先算法进行轮循回收内存资源。其次,对于内存中的垃圾分为两种,一种是需要调用对象的析构函数,另一种是不需要调用的。GC对于前者的回收需要通过两步完成,第一步是调用对象的析构函数,第二步是回收内存,但是要注意这两步不是在GC一次轮循完成,即需要两次轮循;相对于后者,则只是回收内存而已。
很明显得知,对于某个具体的资源,无法确切知道,对象析构函数什么时候被调用,以及GC什么时候会去释放和回收它所占用的内存。那么对于从C、C++之类语言转换过来的程序员来说,这里需要转变观念。
那么对于程序资源来说,我们应该做些什么,以及如何去做,才能使程序效率最高,同时占用资源能尽快的释放。前面也说了,资源分为两种,托管的内存资源,这是不需要我们操心的,系统已经为我们进行管理了;那么对于非托管的资源,这里再重申一下,就是Stream,数据库的连接,GDI+的相关对象,还有Com对象等等这些资源,需要我们手动去释放。
如何去释放,应该把这些操作放到哪里比较好呢。.Net提供了三种方法,也是最常见的三种,大致如下:
1ï¼ ææå½æ°ï¼
2ï¼ ç»§æ¿IDisposableæ¥å£ï¼å®ç°Disposeæ¹æ³ï¼
3ï¼ æä¾Closeæ¹æ³ã
ç»è¿åé¢çä»ç»ï¼å¯ä»¥ç¥éææå½æ°åªè½è¢«GCæ¥è°ç¨çï¼é£ä¹æ æ³ç¡®å®å®ä»ä¹æ¶å被è°ç¨ï¼å æ¤ç¨å®ä½ä¸ºèµæºçéæ¾å¹¶ä¸æ¯å¾åçï¼å 为èµæºéæ¾ä¸åæ¶ï¼ä½æ¯ä¸ºäºé²æ¢èµæºæ³æ¼ï¼æ¯ç«å®ä¼è¢«GCè°ç¨ï¼å æ¤ææå½æ°å¯ä»¥ä½ä¸ºä¸ä¸ªè¡¥ææ¹æ³ãèCloseä¸Disposeè¿ä¸¤ç§æ¹æ³çåºå«å¨äºï¼è°ç¨å®äºå¯¹è±¡çCloseæ¹æ³åï¼æ¤å¯¹è±¡æå¯è½è¢«éæ°è¿è¡ä½¿ç¨ï¼èDisposeæ¹æ³æ¥è¯´ï¼æ¤å¯¹è±¡æå æçèµæºéè¦è¢«æ 记为æ ç¨äºï¼ä¹å°±æ¯æ¤å¯¹è±¡è¢«éæ¯äºï¼ä¸è½å被使ç¨ãä¾å¦ï¼å¸¸è§SqlConnectionè¿ä¸ªç±»ï¼å½è°ç¨å®Closeæ¹æ³åï¼å¯ä»¥éè¿Openéæ°æå¼æ°æ®åºè¿æ¥ï¼å½å½»åºä¸ç¨è¿ä¸ªå¯¹è±¡äºå°±å¯ä»¥è°ç¨Disposeæ¹æ³æ¥æ è®°æ¤å¯¹è±¡æ ç¨ï¼çå¾ GCåæ¶ãæç½äºè¿ä¸¤ç§æ¹æ³çææåï¼å¤§å®¶å¨å¾èªå·±çç±»ä¸æ·»å çæ¥å£æ¶åï¼ä¸è¦æªæ²äºè¿ä¸¤è ææã
æ¥ä¸æ¥è¯´è¯´è¿ä¸ä¸ªå½æ°çè°ç¨æ¶æºï¼æç¨å 个è¯éªç»ææ¥è¿è¡è¯´æï¼å¯è½ä¼ä½¿å¤§å®¶çå°è±¡æ´æ·±ã
é¦å æ¯è¿ä¸ç§æ¹æ³çå®ç°ï¼å¤§è´å¦ä¸ï¼
///
/// The class to show three disposal function
///
public class DisposeClass:IDisposable
   {
public void Close()
       {
           Debug.WriteLine( "Close called!" );
       }
       ~DisposeClass()
       {
           Debug.WriteLine( "Destructor called!" );
       }
       #region IDisposable Members
public void Dispose()
       {
// TODO: Add DisposeClass.Dispose implementation
           Debug.WriteLine( "Dispose called!" );
       }
       #endregion
   }
对äºCloseæ¥è¯´ä¸å±äºçæ£æä¹ä¸çéæ¾ï¼é¤äºæ³¨æå®éè¦æ¾ç¤ºè¢«è°ç¨å¤ï¼æå¨æ¤å¯¹å®ä¸å¤è¯´äºãè对äºææå½æ°èè¨ï¼ä¸æ¯å¨å¯¹è±¡ç¦»å¼ä½ç¨ååç«å»è¢«æ§è¡ï¼åªæå¨å ³éè¿ç¨æè è°ç¨GC.Collectæ¹æ³çæ¶åæ被è°ç¨ï¼åçå¦ä¸ç代ç è¿è¡ç»æã
private void Create()
       {
           DisposeClass myClass = new DisposeClass();
       }
private void CallGC()
       {
           GC.Collect();
       }
// Show destructor
       Create();
       Debug.WriteLine( "After created!" );
       CallGC();
è¿è¡çç»æ为ï¼
After created!
Destructor called!
æ¾ç¶å¨åºäºCreateå½æ°å¤ï¼myClass对象çææå½æ°æ²¡æ被ç«å»è°ç¨ï¼èæ¯çæ¾ç¤ºè°ç¨GC.Collectæ被è°ç¨ã
对äºDisposeæ¥è¯´ï¼ä¹éè¦æ¾ç¤ºçè°ç¨ï¼ä½æ¯å¯¹äºç»§æ¿äºIDisposableçç±»å对象å¯ä»¥ä½¿ç¨usingè¿ä¸ªå ³é®åï¼è¿æ ·å¯¹è±¡çDisposeæ¹æ³å¨åºäºusingèå´åä¼è¢«èªå¨è°ç¨ãä¾å¦ï¼
using( DisposeClass myClass = new DisposeClass() )
   {
//other operation here
   }
å¦ä¸è¿è¡çç»æå¦ä¸ï¼
Dispose called!
é£ä¹å¯¹äºå¦ä¸DisposeClassç±»åçDisposeå®ç°æ¥è¯´ï¼äºå®ä¸GCè¿éè¦è°ç¨å¯¹è±¡çææå½æ°ï¼æç §åé¢çGCæµç¨æ¥è¯´ï¼GC对äºéè¦è°ç¨ææå½æ°ç对象æ¥è¯´ï¼è³å°ç»è¿ä¸¤ä¸ªæ¥éª¤ï¼å³é¦å è°ç¨å¯¹è±¡çææå½æ°ï¼å ¶æ¬¡åæ¶å åãä¹å°±æ¯è¯´ï¼æç §ä¸é¢æåçDisposeå½æ°ï¼è½è¯´è¢«æ§è¡äºï¼ä½æ¯GCè¿æ¯éè¦æ§è¡ææå½æ°ï¼é£ä¹ä¸ä¸ªå®æ´çDisposeå½æ°ï¼åºè¯¥éè¿è°ç¨GC.SuppressFinalize(this )æ¥åè¯GCï¼è®©å®ä¸ç¨åè°ç¨å¯¹è±¡çææå½æ°ä¸ãé£ä¹æ¹ååçDisposeClasså¦ä¸ï¼
///
/// The class to show three disposal function
///
public class DisposeClass:IDisposable
   {
public void Close()
       {
           Debug.WriteLine( "Close called!" );
       }
       ~DisposeClass()
       {
           Debug.WriteLine( "Destructor called!" );
       }
       #region IDisposable Members
public void Dispose()
       {
// TODO: Add DisposeClass.Dispose implementation
           Debug.WriteLine( "Dispose called!" );
           GC.SuppressFinalize( this );
       }
       #endregion
   }
éè¿å¦ä¸ç代ç è¿è¡æµè¯ã
private void Run()
       {
using( DisposeClass myClass = new DisposeClass() )
           {
//other operation here
           }
       }
private void CallGC()
       {
           GC.Collect();
       }
// Show destructor
       Run();
       Debug.WriteLine( "After Run!" );
       CallGC();
è¿è¡çç»æå¦ä¸ï¼
Dispose called!
After Run!
æ¾ç¶å¯¹è±¡çææå½æ°æ²¡æ被è°ç¨ãéè¿å¦ä¸çå®éªä»¥åæå说æï¼å¤§å®¶ä¼å¾å°å¦ä¸çä¸ä¸ªå¯¹æ¯è¡¨æ ¼ã
ææå½æ°
Disposeæ¹æ³
Closeæ¹æ³
æä¹
éæ¯å¯¹è±¡
éæ¯å¯¹è±¡
å ³é对象èµæº
è°ç¨æ¹å¼
ä¸è½è¢«æ¾ç¤ºè°ç¨ï¼ä¼è¢«GCè°ç¨
éè¦æ¾ç¤ºè°ç¨
æè éè¿usingè¯å¥
éè¦æ¾ç¤ºè°ç¨
è°ç¨æ¶æº
ä¸ç¡®å®
ç¡®å®ï¼å¨æ¾ç¤ºè°ç¨æè 离å¼usingç¨åºå
ç¡®å®ï¼å¨æ¾ç¤ºè°ç¨æ¶
é£ä¹å¨å®ä¹ä¸ä¸ªç±»åçæ¶åï¼æ¯å¦ä¸å®è¦ç»åºè¿ä¸ä¸ªå½æ°å°å®ç°å¢ã
æç建议大è´å¦ä¸ã
1ï¼ æä¾ææå½æ°ï¼é¿å èµæºæªè¢«éæ¾ï¼ä¸»è¦æ¯æéå åèµæºï¼
2ï¼ å¯¹äºDisposeåCloseæ¹æ³æ¥è¯´ï¼éè¦çæå®ä¹çç±»åæ使ç¨çèµæºï¼åçåé¢æ说ï¼ï¼èå³å®æ¯å¦å»å®ä¹è¿ä¸¤ä¸ªå½æ°ï¼
3ï¼ 在实现Dispose方法的时候,一定要加上“GC.SuppressFinalize( this )”语句,避免再让GC调用对象的析构函数。
C#程序所使用的内存是受托管的,但不意味着滥用,好地编程习惯有利于提高代码的质量以及程序的运行效率。
(转自 愚翁专栏 http://tb.blog.csdn.net/TrackBack.aspx?PostId=1023352)