根据我的理解,编译了空方法,但实际上并未调用:In .NET, will empty method calls be optimized out?
我还在阅读http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx:
不应使用空的析构函数。 当一个类包含一个析构函数时,一个 在Finalize中创建条目 队列。当析构函数被调用时, 垃圾收集器被调用 处理队列。如果是析构函数 是空的,这只会导致一个不必要的 失去了表现。
这是否意味着使用空的析构函数,仍会在Finalize队列中创建一个条目,但是JIT会阻止调用该方法?
答案 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一次,这意味着没有机会针对您的特定情况进行优化。总的来说,除非你需要,否则最好不要添加终结器。