转自: http://www.cnblogs.com/dc10101/archive/2009/03/16/1413804.html

默认情况下,GC自动回收的资源只有托管堆上的内存,其他资源如数据库连接、流等等都不在GC的管理范围之内,这些资源统称为非托管资源。

当不使用托管资源的时候,默认的析构函数就可以搞定一切。只有在需要手工释放非托管资源的时候才应该(不是必须)重写析构函数。

有一点和C++不一样的地方,在C#里只有类才在托管堆上分配内存,也只有类才有析构函数,struct是不能有析构函数的。所以尽量不要在struct里分配非托管资源,因为struct不得不失去析构函数这一层保障。

GC在工作的时候,会先停下该进程的所有线程。所以对于托管资源,没事的时候不要自己强制进行垃圾回收,会影响性能。只有当很特殊的情况,例如你刚刚分配了一大堆内存,而又马上要进入一个不想被垃圾回收打断的过程,这时候才值得手工垃圾回收。

手工垃圾回收的代码:

GC.Collect();

GC.WaitForPendingFinalizers(); //Suspends the current thread until the thread that is processing the queue of finalizers has emptied that queue.

有三代:0,1,2
0代最有可能被回收
1代次之
2代最不可能被回收
年龄越大的被回收的可能性越小。

当垃圾回收被某个事件触发的时候,会先清理0代,把能清理的都清理了,不能清理的挪到1代。若把0代的清理完了内存还不够用再清理1代,把1代能清理的都清理了,还有用的挪到2代。2代就到头了,不能往后挪了。

托管资源交给GC就好,非托管资源则必须亲自写代码回收。因此对于非托管资源,一般要写一个Dispose方法来实现IDisposable,这样就可以放在using块中自动调用Dispose,也可以显示调用Dispose函数来进行清理。除此之外,最好在析构函数中也释放资源,一旦忘记调用Dispose函数也好有个补救。但不能只依赖析构函数,因为GC什么时候开始进行垃圾回收还不一定,对象处于第几代也不能事先确定,所以等到GC启动了可能某些稀缺资源早就耗尽了。

下面是MSDN上的best practice,非常有参考价值:
实现IDispose: http://msdn.microsoft.com/zh-cn/library/system.idisposable.dispose.aspx

有继承关系的类的Dispose:

// Design pattern for a base class.
    public class Base : IDisposable
        private bool disposed = false;
        //Implement IDisposable.
        public void Dispose()
            Dispose(true);
            GC.SuppressFinalize(this); // Prevent finalization code executing
        protected virtual void Dispose(bool disposing)
            if (disposed)
                return;
            if (disposing)
                // TODO: Release managed resources.
            // TODO: Release unmanaged resources.          
        // Use C# destructor syntax for finalization code.
        ~Base()
            // Simply call Dispose(false).
            Dispose(false);
    // Design pattern for a derived class.
    public class Derived : Base
        protected override void Dispose(bool disposing)
            if (disposed)
                return;
            if (disposing)
                // TODO: Release managed resources.
            // TODO: Release unmanaged resources.
            // Call Dispose on your base class.
            base.Dispose(disposing);
        // The derived class does not have a Finalize method
        // or a Dispose method without parameters because it inherits
        // them from the base class.
 

上面一段代码中有一点我还不太明白,即为什么析构函数用Dispose(false),而不敢去释放托管资源,在MSDN上找到的解释是:

Dispose(bool disposing) executes in two distinct scenarios. If disposing equals true, the method has been called directly or indirectly by a user's code and managed and unmanaged resources can be disposed. If disposing equals false, the method has been called by the runtime from inside the finalizer and only unmanaged resources can be disposed. When an object is executing its finalization code, it should not reference other objects, because finalizers do not execute in any particular order. If an executing finalizer references another object that has already been finalized, the executing finalizer will fail.

它说在析构函数中引用的某些对象有可能已经被释放了,所以再去释放它们是不对的。似乎有点儿道理,但问题是,如果析构函数不被调用,那么包含在这个类中的其他对象的引用怎么可能被析构了呢?

转自:http://www.cnblogs.com/dc10101/archive/2009/03/16/1413804.html默认情况下,GC自动回收的资源只有托管堆上的内存,其他资源如数据库连接、流等等都不在GC的管理范围之内,这些资源统称为非托管资源。当不使用托管
文章目录前言一、垃圾回收是什么二、好处三、GC过程1.GC条件2.GC步骤3.Mark-Compact 标记压缩算法4.Generational 分代算法5.Finalization Queue和Freachable Queue四、托管和非托管资源1.托管资源2.非托管资源五、GC注意事项参考 C#的垃圾回收网上有很多博客进行讲解,这里摘录一部分较好的讲解,同时建议直接使用微软官方文档,万变不离其宗 一、垃圾回收是什么 .NET 的垃圾收集器管理应用程序的内存分配和释放。每次创建新对象时,公共语.
http://www.cnblogs.com/fdyang/p/3456258.html (c#) 销毁资源和释放内存 https://www.cnblogs.com/Jessy/articles/2552839.html C# Finalize和Dispose的区别 https://www.cnblogs.com/wuyuankun/p/4103620.html C#中标...
垃圾回收 在讨论垃圾回收之前,需要明白一个重要的事情,空间是怎么被分配出去的。在进程初始化时,CLR会保留一块连续的地址空间(托管堆),托管堆中维护着一个指针,称之为NextObjPtr,它指向下一个对象在堆中的分配位置。当我们在C#中调用new关键字的时候,编译器会自动生成IL指令newobj,该指令将导致CLR执行以下步骤: 计算类型(及其所有基类型)的字段,类型对象指针和同步块索引所需要的字节数。 检查是否有足够的空间储存,有的话,将对象储存在NextObjPtr指向的空间中,调用类型实例
C#中的connectionstring是指连接字符串,用于连接数据库。它包含了数据库的地址、用户名、密码等信息,可以通过它来建立与数据库的连接。在C#中,我们可以使用System.Data.SqlClient命名空间中的SqlConnection类来创建数据库连接,并使用connectionstring来指定连接字符串。例如: string connectionString = "Data Source=myServerAddress;Initial Catalog=myDataBase;User ID=myUsername;Password=myPassword;"; SqlConnection connection = new SqlConnection(connectionString); connection.Open(); //执行数据库操作 connection.Close();