当前位置:编程学习 > C#/ASP.NET >>

c#高性能编码三

1 原则上禁止使用GC.Collect 方法
 
显式执行GC.Collect()有可能给内存回收增加负担,而且不一定能真正回收内存,垃圾回收周期是不确定的,由垃圾回收器引擎自动计算最佳的垃圾回收时间。在一个需要大量消耗内存的应用程序中,如果在某个确定的时间点上已经明确占用的内存不再需要,及时释放这些内存对提高应用程序的性能有显著的影响,这时就可以强制垃圾回收器执行回收周期。
 
GC.Collect方法强制垃圾回收器执行垃圾回收周期。在应用程序中调用GC.Collect方法可以强制垃圾回收,及时释放不再需要的大量内存。但是过于频繁的调用GC.Collect方法同样也会带来应用程序的性能问题。因为,开始执行垃圾回收线程时,垃圾回收器将挂起当前正在执行的所有线程,直到垃圾回收线程结束;另一方面,频繁的调用GC.Collect方法还将削弱垃圾回收器引擎的优化作用。而在通常情况下,垃圾回收器往往可以确定最佳的垃圾回收时间。原则上禁止使用,如果有特殊情况需要使用,要求进行代码评审
 
 2 如果释放非托管资源,建议采用dispose模式
 
类实例经常封装对不受运行库管理的资源(如窗口句柄 (HWND)、数据库连接等)的控制。因此,应该既提供显式方法也提供隐式方法来释放这些资源。通过在对象上实现受保护的Finalize 方法(在 C#中为析构函数语法)可提供隐式控制。当不再有任何有效的对象引用后,垃圾回收器在某个时间调用此方法。
 
在有些情况下,可能想为使用该对象的程序员提供显式释放这些外部资源的能力,以便在垃圾回收器释放该对象之前释放这些资源。当外部资源稀少或者昂贵时,如果程序员在资源不再使用时显式释放它们,则可以获得更好的性能。若要提供显式控制,请实现由IDisposable接口提供的Dispose方法。在完成使用该对象的操作时,该对象的使用者应调用此方法。即使对对象的其他引用是活动的,也可以调用Dispose。
 
正例:
 
//基类模式.
 
public class Base: IDisposable
 
{
 
   //实现 Idisposable接口.
 
   public void Dispose()
 
   {
 
      Dispose(true);
 
      GC.SuppressFinalize(this);
 
   }
 
 
 
   protected virtual void Dispose(bool disposing)
 
   {
 
      if (disposing)
 
      {
 
         //其他状态 (托管 objects).
 
      }
 
      //释放状态 (非托管对象)    
 
   }
 
 
 
   // 用 C# 析构函数来负责 finalization 的代码
 
   ~Base()
 
   {
 
      Dispose (false);
 
   }
 
}
 
//子类模式.
 
public class Derived: Base
 
{  
 
   protected override void Dispose(bool disposing)
 
   {
 
      if (disposing)
 
      {
 
         //释放托管资源.
 
      }
 
      //释放非托管资源
 
      //调用基类的Dispose方法
 
      base.Dispose(disposing);
 
   }
 
   //子类不需要Finalize方法或者无参数的Dispose方法,因为它从基类继承了
 
}
 
3 如果有IO操作,建议使用Buffer缓冲区
 
说明:在IO操作时,输入输出流实际的长度未知的情况下,比如:网络流。可以先初始化一段缓存,再将流读出来的流信息写到内存流里面,这样可以提高性能并且安全
 
正例:
 
publicstaticbyte[] ReadFully(Stream stream)
 
 {   //初始化一个8k的缓存
 
     byte[] buffer = new byte[8192];
 
     using ( MemoryStream ms = new MemoryStream() )
 
     {
 
//返回结果后会自动回收调用该对象的Dispose方法释放内存
 
          while ( true )
 
          {
 
               int read = stream.Read(buffer, 0, buffer.Length);
 
               if ( read <= 0 )
 
               {
 
                   return ms.ToArray();
 
                }
 
                ms.Write(buffer, 0, read);
 
            }
 
      }
 
}
 
4 不允许使用空析构函数
 
如果类包含析构函数,创建对象时会在 Finalize队列中添加对象的引用,以保证当对象无法可达时,仍然可以调用到 Finalize方法。垃圾回收器在运行期间,会启动一个低优先级的线程处理该队列。相比之下,没有析构函数的对象就没有这些消耗。如果析构函数为空,这个消耗就毫无意义,只会导致性能降低。因此,不要使用空的析构函数。
 
5  递归和循环   在循环体内避免耗资源的操作,如创建大对象,把这些操作提到循环体外面
 
说明:在循环体内如果有获取某个变量值的操作,且和循环变量无关的情况,可以把此操作提取到循环外,用临时变量替代此数值,避免无谓的耗资源
 
正例:
 
 
 
Database db = new Database();
 
DataTable dt = db.LoadSql(“select id from emps”);
 
foreach( int i = 0 ; i < 5000 ; i++ )
 
{           
 
    Emp objEmp = dt.select(“id=” + i, dt);
 
    。。。
 
}
 
反例:
 
foreach( int i = 0 ; i < 5000 ; i++ )
 
{           Database db = new Database();
 
    //这里读取数据库是昂贵的操作,且操作和循环无关, 应该用一个临时变量
 
//记录,并且在变量中使用
 
Emp objEmp = Business.FindEmp(“id=” + i, db.LoadSql(“select id from emps”));
 
}
 
 
 
正例:
 
 
 
Class objClassa=new Class();
 
foreach( Class objClassb in Classs)
 
{           
 
    objClassa.a=objClassb.b;
 
     ...
 
}
 
反例:
 
foreach( Class objClass in Classs)
 
补充:软件开发 , C# ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,