C#中的垃圾回收及资源管理器

来源:互联网 发布:外服盒子mac 编辑:程序博客网 时间:2024/04/28 13:32
 变量和对象一经创建,就将在内存上为其分配空间,为了回收宝贵的内存资源,程序应该在合适的时候将该对象或者变量进行销毁。下面,总结几种方式:
一、垃圾回收器——析构器
    
C#中,能创建一个对象的无数引用。对同一对象的引用的数量决定了对象的生存期。
[csharp] view plaincopyprint?
  1. Square mySquare=new mySquare();  
  2. Square anotherSquare=mySquare;  

    一个变量(mySquare)消失,其他变量(anotherSquare)仍可能继续存在。所以,一个对象的生存期不能同一个特定的引用变量挂钩。只有在对一个变量的所有引用消失之后,才可以销毁这个对象。
    为什么要用垃圾回收器?
    1)不使用的问题:
         A)忘记销毁对象
         B)试图销毁一个活动对象,如果销毁了,会造成虚悬引用(dangling reference)
         
C)试图多次销毁同一对象
    2)垃圾回收器的几点好处
         A)每个对象都会被销毁,它的析构器会被调用
         B)每个对象只销毁一次
         C)每个对象只有在它不可抵达时(unreachable)时,换言之,不再存在到该对象的任何引用——才会摧毁。
    只有当对象进行垃圾回收时,才会运行析构器。一些指导思想:
    1)慎用析构函数,垃圾回收器会影响程序的运行速度
    2)“终结”(调用析构函数的过程称为“终结”)的顺序是得不到任何保证的,所以,要确定析构器不要相互依赖、或者相互重叠。
二、资源管理
    有的时候,用析构器释放一个资源是一种不明智的行为,有的资源可能过于宝贵,用完后应该马上释放。在这种情况下,唯一的选择就是亲自释放资源。
    “disposal方法”强调的方的用途而不是。换言之,一个disposal方法可以使用任何有效的C#方法名,而不说专门有一个名为disposal的方法。
    2.1 disposal方法

[csharp] view plaincopyprint?
  1. TextReader reader= new StreamReader(fileName);  
  2. string line;  
  3. while((line=reader.ReadLine())!=null)  
  4. {  
  5.     Console.WriteLine(line);  
  6. }  
  7. reader.Close();  

    很有可能在运行reader.Close()之前,程序就抛出了异常,那么最终会耗尽文件句柄资源,无法打开任何更多的文件。
    2.2 异常安全的disposal方法    
    为了确保disposal方法(例如Close)总是得到调用——无论是否发生异常——一个办法是在finally块中调用disposal方法。
[csharp] view plaincopyprint?
  1. TextReader reader= new StreamReader(fileName);  
  2. try  
  3. {  
  4.     string line;  
  5.     while((line=reader.ReadLine())!=null)  
  6.     {  
  7.          Console.WriteLine(line);  
  8.     }  
  9. }  
  10. finally  
  11. {  
  12.     reader.Close();  
  13. }  
    使用finally块是可行的,但由于它存在几个缺点,所以并不是一个十分理想的方案:
    1)如果必须摧毁多个资源,局面很快就会变得难以控制(最终将获得大量嵌套的try和finally块)
    2)它不能创建解决方案的一个抽象
    3)对资源的引用保留在finally块之后的作用域中
三、using语句(推荐方案)
    
using语句提供了一个脉络清晰的机制来控制资源的生存期。可以创建一个对象,这个对象会在using语句块结束时销毁。
    在using语句中声明的变量必须是实现了IDisposable接口的一个类型。IDisposable接口在System命名空间中,只包含一个名为Dispose方法。using语句具有以下功能:
    1)需要dispose多个资源时,具有良好的扩展性
    2)不影响程序代码的逻辑
    3)对问题进行良好的抽象,避免重复性编码
    4)非常健壮,using语句结束后,就不能使用using语句中声明的变量,因为其已经不在作用域中。如果坚持使用,会产生编译时错误。
四、从析构器中调用Dispose方法
    
1)类实现了IDisposable接口
    2)析构器调用Dispose
    3)Dispose方法是public方法,可以在任何时候调用
    4)Dispose方法可以安全地多次调用
    5)Dispose方法调用静态方法GC.SuppressFinalize
    6)类的所有常规方法都要检查对象是否disposed;如果是,就抛出一个异常。
五、强制垃圾回收
    
可以调用静态方法System.GC.Collect,从而在一个程序中调用垃圾回收器。System.GC.Collect方法将启动垃圾回收器,但具体的回收过程是异步进行的。当方法结束时,程序员仍然不知道对象是否已经摧毁。
原创粉丝点击