• 你需要知道的c# Timer 的垃圾回收机制。


    通常我们需要定时执行一段任务的时候,我们就需要定时器,这时我们就可以使用c# System.Threading空间中的 Timer定时器;他是个异步定时器,时间到时每次都是在线程池中分配一个线程去执行任务。下面我们来看一个有趣的例子:

     class Program
        {
            static void Main(string[] args)
            {
                Timer timer = new Timer(TimerCallback,null,0,2000);
                
                Console.ReadLine();
            }
    
            private static void TimerCallback(object o)
            {
                Console.WriteLine("in TimerCallback method");
                GC.Collect();
    
                
            }
        }
    

    当我们在debug模式下运行该段程序时,正如我们期盼的那样程序会每隔2秒钟执行该方法,打印出"in TimerCallback method”,而在release模式下执行的时候,只执行一次该方法,字符串只打印一次。在这里我们在调用TimerCallback方法时,强制执行垃圾回收器,说明在release模式下,垃圾回收器执行回收算法时,首先假设所有对象都是可回收的,当将Timer对象赋值给变量t后,t没有在被引用,因此也就没有变量引用Timer对象,所以垃圾收集这时会回收Timer对象。那么为什么在debug模式下却能够运行能,这跟c#编译器的优化方式有关,在release模式下编译器做了相关的优化操作。而在debug模式下,timer对象的生成期是方法的结束,这样做也是为了调试的方便。要不然在调试时,我们执行到Timer timer = new Timer()后想看timer的值时,已经被垃圾回收器给回收了,这是我们不期望看到的结果,编译器如何处理的,我们可以看看编译器在release模式下和debug模式下对上面的代码编译后生成的IL对比我们既知结果。

    release模式编译生成的IL:

     1 .method private hidebysig static void  Main(string[] args) cil managed
     2 {
     3   .entrypoint
     4   // Code size       32 (0x20)
     5   .maxstack  8
     6   IL_0000:  ldnull
     7   IL_0001:  ldftn      void GCTest.Program::TimerCallback(object)
     8   IL_0007:  newobj     instance void [mscorlib]System.Threading.TimerCallback::.ctor(object,
     9                                                                                      native int)
    10   IL_000c:  ldnull
    11   IL_000d:  ldc.i4.0
    12   IL_000e:  ldc.i4     0x7d0
    13   IL_0013:  newobj     instance void [mscorlib]System.Threading.Timer::.ctor(class [mscorlib]System.Threading.TimerCallback,
    14                                                                              object,
    15                                                                              int32,
    16                                                                              int32)
    17   IL_0018:  pop
    18   IL_0019:  call       string [mscorlib]System.Console::ReadLine()
    19   IL_001e:  pop
    20   IL_001f:  ret
    21 } // end of method Program::Main

    debug模式下生成的IL:

     1 method private hidebysig static void  Main(string[] args) cil managed
     2 {
     3   .entrypoint
     4   // Code size       33 (0x21)
     5   .maxstack  4
     6   .locals init ([0] class [mscorlib]System.Threading.Timer timer)
     7   IL_0000:  nop
     8   IL_0001:  ldnull
     9   IL_0002:  ldftn      void GCTest.Program::TimerCallback(object)
    10   IL_0008:  newobj     instance void [mscorlib]System.Threading.TimerCallback::.ctor(object,
    11                                                                                      native int)
    12   IL_000d:  ldnull
    13   IL_000e:  ldc.i4.0
    14   IL_000f:  ldc.i4     0x7d0
    15   IL_0014:  newobj     instance void [mscorlib]System.Threading.Timer::.ctor(class [mscorlib]System.Threading.TimerCallback,
    16                                                                              object,
    17                                                                              int32,
    18                                                                              int32)
    19   IL_0019:  stloc.0
    20   IL_001a:  call       string [mscorlib]System.Console::ReadLine()
    21   IL_001f:  pop
    22   IL_0020:  ret
    23 } // end of method Program::Main

    从生成的IL中我们可以看出在debug模式下,生成IL比在release模式下多了19行红色字体的IL指令码,该指令码的作用是将15行生成的引用Timer对象的栈上的变量存放到局部变量0中。所以使得在debug模式下该t还被引用,不能够回收Timer对象,所以也能出现我们期盼的结果,那么如何在两种模式下都能得到我们期盼的结果呢。我们可以如下操作。

    正确的代码:

     1   class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Timer timer = new Timer(TimerCallback,null,0,2000);
     6         
     7             Console.ReadLine();
     8             timer.Dispose();
     9         }
    10 
    11         private static void TimerCallback(object o)
    12         {
    13             Console.WriteLine("in TimerCallback method");
    14 
    15             GC.Collect();
    16 
    17             
    18         }
    19     }

    这时不管是在release模式下还是debug模式下,都会每隔2秒钟调用我们的回调方法。

  • 相关阅读:
    VSS與CSV區別
    办公室中节约时间
    C#中用Smtp發郵件
    关于分层结构的感悟(轉)
    Visual Studio.Net 技巧(轉)
    常用數據庫訪問方式比較
    Winows部署中一些內容說明
    适配器模式(Adapter Pattern)(轉)
    Vistual Studio 2005 sp1補丁的詳細內容
    感情 程序 祭 【转】
  • 原文地址:https://www.cnblogs.com/justinli/p/timer.html
Copyright © 2020-2023  润新知