垃圾回收机制(GC)总结报告(三)

1、Finalize方法
    Finalize方法要做的事情通常是回收垃圾回收器不能回收的资源,例如文件句柄,数据库连接(非托管资源的释放)
(1)第一次垃圾回收
    对象B、E、G、H、I和J被标记为垃圾--->添加到Freachable队列:
(1)没有Finalize方法,直接回收
(2)有Finalize方法,一个独立的线程finalizer thread异步进行处理调用finalize method
(2)再一次垃圾回收
实现Finalize方法的对象才被真正的回收。这些对象的Finalize方法已经执行过了,Freachable队列也清空了。
整个过程中,需要两次垃圾回收才能收回这些对象占有的内存。实际情况下可终结对象会被提升代,所以可能需要不止两次回收才能收回这些对象占有的内存。

         这类资源,垃圾回收器在清理的时候会调用Object.Finalize()方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。
在.NET中,Object.Finalize()方法是无法重载的,编译器是根据类的析构函数来自动生成Object.Finalize()方法的,所以对于包含非托管资源的类,可以将释放非托管资源的代码放在析构函数。
备注:
(1)提供析构函数,避免资源未被释放,主要是指非内存资源;
(2)对于Dispose和Close方法来说,需要看所定义的类型所使用的资源(参看前面所说),而决定是否去定义这两个函数;
(3)在实现Dispose方法的时候,一定要加上“GC.SuppressFinalize( this )”语句,避免再让GC调用对象的析构函数。
   /// <summary>
   /// The class to show three disposal function
   /// </summary>
   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
   }

 
析构函数
Dispose方法
Close方法
意义
销毁对象
销毁对象
关闭对象资源
调用方式
不能被显示调用,会被GC调用
需要显示调用
或者通过using语句
需要显示调用
调用时机
不确定
确定,在显示调用或者离开using程序块
确定,在显示调用时
2、线程劫持与工作站模式:
    当GC开始内测回收的时候,所有线程都必须挂起,因为这些线程不能再访问内存中的对象。(这是因为GC线程要压缩内存,压缩过程中,对象的引用可能变得无效,所以只能在GC完成后,其他线程才能继续执行。)
    等待线程进入一个安全点,GC就会开始生效,CLR会对其他线程进行劫持,所有这些线程都进入了同一个方法,并且都试图获取同一个临界区。

    工作站模式(Workstation)并发方式非并发方式(阻塞式GC)、后台GC模式(.net4.0后)
    服务器模式(Server):非并发方式(Non-concurrent)、后台GC模式(.net4.5后)

默认为工作站模式的并发方式,并且总是运行在单核的CPU上(单核CPU有且仅能工作站模式)
<configuration>
   <runtime>
      <gcServer enabled="true|false"/>
      <gcConcurrent enabled="true|false"/>
   </runtime>
</configuration>
工作站模式工作情况:
    无论是在工作站模式还是在服务器模式上,只要是非并发方式都称为阻塞式GC。因为这种方式下,GC运行的时候,都会挂起对应CPU上的所有托管线程,然后清理内存完毕后,才恢复挂起的内存。在这期间,其他的代码是无法运行的。

开启了并发GC的情况下:
    由于第0代和第1带的回收非常的快(毫秒级),所以在第0代和第1代上的回收是不做并发的,只有在第2代回收时才会并发。当第2代回收的时候,有一个专门的GC线程去做(和其他托管线程并发运行),其他托管线程只能在第0代和第1代上分配空间。

服务器模式下:每个CPU有一个线程专门执行GC作业,并且托管的堆也会被分成好几个区域,每个线程回收它自己的托管堆,并且这些线程都是最高优先权的,这些线程都只做GC操作,这就使得GC速度很快,但也意味着用户线程会阻塞。服务器模式适合服务器应用程序,只关注高的响应率。

    在.NET4.0的时候,并发模式的升级版,并且默认是开启的,这种后台方式将会替代并发模式的。
    后台GC可以同时在第0、1、2代上执行。这时第0、1 代上的垃圾收集被称为前台GC(即阻塞式GC)。后台GC,则可以启动另一个临时GC,与并发GC相同,后台GC只运用于完全的垃圾回收(第0、1、2代)并工作在独立的GC线程中。

3、弱引用
    弱引用,指的是一个变量可以被垃圾回收了。这个对象不会用了,但是日后又担心会用,而且这个对象的创建非常耗时,我们就要用弱引用,需要注意的是,弱引用引用起来的对象是可以被垃圾回收的,但只要没被垃圾回收(能引用得到),就可以继续使用。
        Person p = new Person() { ID = 1,Name = "张三",BirthDate = DateTime.Now };  //对象初始化器               
        WeakReference wReference = new WeakReference(p);        //将p对象弱引用起来        
        p = null;

        //手动调用垃圾回收    
        //GC.Collect();          
           
        object o = wReference.Target;
        if(o != null && wReference.IsAlive) {
            Person p1 = o as Person;
            Console.WriteLine(p1.ID + "==" + p1.Name + "==" + p1.BirthDate);
        } else {
            Console.WriteLine("对象被垃圾回收了,请重新创建对象吧");
        }
虽然将p指向了null,但是因为还没被回收,我们通过弱引用(WeakReference)能找到它,便可继续使用。【注释GC.Collect()】 

弱引用的适用场景:
1.创建一个对象非常耗时;
2.这个对象不会用了(可以被垃圾回收),但是日后又担心会用;
3.弱引用的对象也不是一定就存在,如果手动调用GC.Collect()或者正好被垃圾回收,也会引用不到,此时若要用,只能重新创建对象。
4、代龄与分代算法
        .NET将heap分成3个代龄区域: Gen 0、Gen 1、Gen 2    
        垃圾回收是在第0代满的时候发生的。使用代(generation)的机制的唯一目的就是提高性能。基本思路是,第0代是最近分配的对象,从未被垃圾回收算法检查过。在一次垃圾回收中存活下来的对象被提升到另一代。如经过一次垃圾回收,第0代被提升为第1代;第1代被提升为第2代。
    
    第0代:局部变量
    第1代(通常为2 MB)是经过0代垃圾收集后仍然驻留在内存中的对象,它们通常是表单,按钮等对象
    第2代是经历过几次垃圾收集后仍然驻留在内存中的对象,它们通常是一些应用程序对象


(1)如果Gen 0 heap内存达到阀值,则触发0代GC,0代GC后Gen 0中幸存的对象进入Gen 1。
(2)如果Gen 1的内存达到阀值,则进行1代GC,1代GC将Gen 0 heap和Gen 1 heap一起进行回收,幸存的对象进入Gen 2。
(3)2代GC将Gen 0 heap、Gen 1 heap和Gen 2 heap一起回收

    内存吃紧时(例如0代对象充满),GC便被调入执行引擎——也就是CLR——开始对第0代的空间进行标记与压缩工作、回收工作。特别的,当对第2代回收后任然无法获得足够的内存,那么系统就会抛出OutOfMemoryException
    当经过几次GC过后,0代中的某个对象仍然存在,那么它将被移动到第1代。同理,第1、2代也按同样的逻辑运行。GC Heap中代的数量与容量,都是可变的。

下面的示例强制的第 2 代对象进行垃圾回收Optimized设置。
 GC.Collect(2, GCCollectionMode.Optimized);
    备注:Optimized是一个枚举值,指定垃圾回收是强制进行(GCCollectionMode.Default 或 GCCollectionMode.Forced)还是优化 (GCCollectionMode.Optimized)。

猜你喜欢

转载自blog.csdn.net/yuewei19/article/details/80339274