最近我在看.NET的垃圾回收机制。其中有一个很有意思的地方,垃圾回收在调试的时候有不一样的处理,在这里我贴出来给大家分享一下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Timer t = new Timer(TimerCallBack1, null, 0, 2000);
Console.Read();
}
static void TimerCallBack1(object o)
{
Console.WriteLine("222");
GC.Collect();
}
}
}
上边的代码在Debug和Relase下编译,会产生不同的结果。
Debug下会不断打印222
而release只会打印一次。
为什么呢?
其实release才是真正正确的结果。因为在TimerCallBack1方法里面,做了一次垃圾回收,回收开始时,垃圾回收器首先假定堆中所有的对象都是不可到达的(垃圾),这当然也包括Timer对象。然后,垃圾回收器检查应用程序的根,发现初始化后,Main方法再也没有用过变量t。既然应用程序没有任何变量引用Timer对象,垃圾回收就回收了Timer对象,回收了timer对象的内存;这使计时器停止触发。
而debug是因为有优化,JIT编译器在生成方法的内部根表时,会将所有的变量的生存期手动延长至方法结束。所以它认为变量t一定要到方法结束才被回收,即console.read()之后。所以计时器一直有效。