C#GC原理

C#垃圾回收机制

CLR:公共运行时环境,管理托管堆。

CTR:设置引用类型,值类型。

GC:只负责回收托管对象,不负责回收非托管对象。

垃圾回收器的基本假定:
         1.
被分配内存空间的对象最有可能被释放。在方法执行时,就需要为该方法的对象分配内存空间,搜索最近分配的对象集合有助于花费最少的代价来尽可能多地释放内存空间。
        2.
生命期最长的对象释放的可能性最小,经过几轮垃圾回收后,对象仍然存在,搜索它时就需要进行大量的工作,却只能释放很小的一部分空间。
        3.
同时被分配内存的对象通常是同时使用,将它们彼此相连有助于提高缓存性能和回收效率
C#
中的回收器是分代的垃圾回收器(Gererational GarbageCollector) 它将分配的对象分为3个类别或代。(可用GC.GetGeneration方法返回任意作为参数的对象当前所处的代)最近被分配内存的对象被放置于第0代,因为第0代很小,小到足以放进处理器的二级(L2)缓存,所以它能够提供对对象的快速存取。经过一轮垃圾回收后,仍然保留在第0代中的对象被移进第1代中,再经过一轮垃圾内存回收后,仍然保留在第1代中的对象则被移进第2代中,第2代中包含了生存期较长的对象。
     
C#中值类型是在堆栈中分配内存,它们有自身的生命周期,所以不用对它们进行管理,会自动分配和释放。而引用类型是在堆中分配内存的。所以它的分配和释放就需要像回收机制来管理。C#为一个对象分配内存时,托管堆可以立即返回新对象所需的内存,因为托管堆类似于简单的字节数组,有一个指向第一个可用内存空间的指针,指针像游标一样向后移动,一段段内存就分配给了正在运行的程序的对象。在不需要太多垃圾回收的程序小,托管堆性能优于传统的堆。
     
当第0代中没有可以分配的有效内存时,就触发了第0代中的一轮垃圾回收,它将删除那些不再被引用的对象,并将当前正在使用的对象移至第1代。而当第0代垃圾回收后依然不能请求到充足的内存时,就启动第1代垃圾回收。如果对各代都进行了垃圾回收后仍没有可用的内存就会引发一个OutOfMemoryException异常。

Public class BaseResource:IDisposable

   {

     PrivateIntPtr handle; // 句柄,属于非托管资源

     PrivateComponet comp; // 组件,托管资源

      PrivatebooisDisposed = false; //是否已释放资源的标志

      

扫描二维码关注公众号,回复: 3702682 查看本文章

     PublicBaseResource

      {

      }

       

       //实现接口方法

       //由类的使用者,在外部显示调用,释放类资源

       Public void Dispose()

      {

          Dispose(true);// 释放托管和非托管资源

                          

         //将对象从垃圾回收器链表中移除,

        // 从而在垃圾回收器工作时,只释放托管资源,而不执行此对象的析构函数

 

           GC.SuppressFinalize(this);

        }

        

        //由垃圾回收器调用,释放非托管资源

 

       ~BaseResource()

       {

          Dispose(false);// 释放非托管资源

       }

       

     //参数为true表示释放所有资源,只能由使用者调用

    //参数为false表示释放非托管资源,只能由垃圾回收器自动调用

   //如果子类有自己的非托管资源,可以重载这个函数,添加自己的非托管资源的释放

  //但是要记住,重载此函数必须保证调用基类的版本,以保证基类的资源正常释放

   Protectedvirtual void Dispose(bool disposing)

    {

      If(!this.disposed)// 如果资源未释放 这个判断主要用了防止对象被多次释放

        {

           If(disposing)

           {

              Comp.Dispose();// 释放托管资源

            }

                           

          closeHandle(handle);// 释放非托管资源

           handle= IntPtr.Zero;

          }

         this.disposed= true; // 标识此对象已释放

      }

  }

在垃圾回收时尽量避免使用finallize来回收资源,这样会造成两车垃圾回收,影响效率

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

猜你喜欢

转载自blog.csdn.net/qq_20949153/article/details/52188882