在.Net环境中,我们需要考虑我们的程序所运行的线程及任何时候垃圾回收都可能发生的事实。我们需要在设计我们的计时代码时将这些因素考虑在内。
让我们先来看一下怎样控制垃圾回收。首先,我们讨论一下垃圾回收的作用。在C#中,引用类型(如字符串,数组及类的实例对象)的内存空间是在被称作堆的空间中分配的。堆是一片用来保存数据项(之前提到的类型)的内存空间。值类型,如普通的变量,被存储在栈上。到引用类型数据的引用也是存储在栈上,但是引用类型中实际存储的数据被保存在栈中。存储在栈上的变量当声明它的子程序执行完成时被释放。另一方面,存储在托管堆上的变量一直存在堆中直到垃圾回收过程被调用。堆数据只有在没有对它的动态引用时通过垃圾回收被移除。垃圾回收可以并且将会发生在程序执行的任意时刻。然而,我们要尽我们可能的确保垃圾回收器在我们计时代码执行的过程中不运行。我们可以通过强制调用垃圾回收器来阻止任意执行的垃圾回收。.Net环境中提供了与个特殊的对象 – GC供调用垃圾回收使用。要通知系统执行垃圾回收。我们简单的写:
GC.Collect();
然而,这不是全部我们必须做的。存储在堆中的每一个对象有一个成为终结器的特殊方法。终结器方法在对象被删除前的最后一步执行。终结器方法存在的问题是它们不以一种规律的方式执行。事实上,你甚至根本不能确定一个对象的终结器是否已经运行了。但是我们知道,在我们确定一个对象被删除之前,它的终结器方法一定会运行。要确保这一点,我们添加一行代码来告诉程序等待所有堆上的对象的终结器方法运行后再继续执行。这行代码如下:
GC.WaitForPendingFinalizers();
我们已经清除了一个障碍并且只剩一个待解决 – 使用适当的线程。在.Net环境中,一个程序运行在一个线程中,也被称作应用程序域。这允许操作系统将每一个不同的程序分开在其上同时运行。在一个进程中,程序或者程序的一部分在一个线程内运行。一个程序的执行时间被操作系统通过线程进行分配。当我们为一个程序的代码计时时,我们想要确保我们计的时间只是进程分配给我的程序的代码所占用的时间,而不是操作系统执行的其他任务的时间。
我们可以使用.NET类库中的Process类来实现这个功能。Process类的方法允许我们选择当前进程(我们的程序正运行的进程),程序正运行的线程,及一个计时器来存储线程开始执行的时间。所有这些方法可合并入一次调用,并指定这个调用函数的返回值为存储线程开始执行的时间(一个TimeSpan对象)的变量。如下是代码(共有两行)。
TimeSpan startingTime;
startingTime = Process.GetCurrentProcess().Threads[0] .UserProcessorTime;
剩下的我们只需捕获我们计时的代码段停止的时间。代码示例如下:
duration = Process.GetCurrentProcess().Threads[0].UserProcessorTime .Subtract(startingTime);