空的析构函数是否优化?

时间:2011-06-09 22:01:00

标签: .net

根据我的理解,编译了空方法,但实际上并未调用:In .NET, will empty method calls be optimized out?

我还在阅读http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx

  

不应使用空的析构函数。   当一个类包含一个析构函数时,一个   在Finalize中创建条目   队列。当析构函数被调用时,   垃圾收集器被调用   处理队列。如果是析构函数   是空的,这只会导致一个不必要的   失去了表现。

这是否意味着使用空的析构函数,仍会在Finalize队列中创建一个条目,但是JIT会阻止调用该方法?

3 个答案:

答案 0 :(得分:2)

JIT通过在编译代码中内联它们来优化正常空方法(或其他简短方法,如大多数getter和setter):通常会出现对方法的调用,而是放置方法的整个主体。

在许多情况下,从性能角度来看,内联不值得,因此编译器不会内联它们,主要是当方法长于几条指令时。

在某些情况下,内联不可能,如递归或虚拟方法。由于终结器(也称为析构函数)实际上只是覆盖虚方法object.Finalize(),因此编译器无法内联它,因此实际调用该方法,即使它是空的。

但是调用方法所带来的性能很小。 GC处理终结器所需的开销要大得多,因此无论内联如何,都不应使用空终结器创建类。这就是您在实施the Dispose pattern时使用GC.SuppressFinalize()的原因。

答案 1 :(得分:1)

它没有优化远离IL。我不能代表Just-In-Time编译的机器代码。

我通过创建一个小类,编译它,然后运行ILDasm来查看IL来验证这一点。

要验证它是否已放入finalize队列,您需要执行此操作:

class Asdf
{
  ~Asdf (){}
}
static void Main ()
{
  new Asdf ();
  GC.Collect ();
  Console.WriteLine ("Now, use ADPLUS to create a memory dump");
  Console.ReadLine ();
}

// Instantiate and Asdf object with an empty finalizer.
// Force Garbage Collection with GC.Collect (); This moves it to the finalize queue.
// Create a memory dump with adplus.exe
// Open a windbg session and .load sos           (son of strike)
// Use the !Dumpheap -type Asdf
// If there is an entry for Asdf, then it is in the finalize queue.

答案 2 :(得分:1)

调用终结器与调用其他方法不同。它更类似于使用委托。实际上,JIT对目标的了解不够,无法优化方法调用,这意味着您的方法将被调用并且只会返回。

编辑:另一点,无论调用终结器的CLR的任何部分都将被JIT一次,这意味着没有机会针对您的特定情况进行优化。总的来说,除非你需要,否则最好不要添加终结器。