3

From what I understand, empty methods are compiled, but not actually called: In .NET, will empty method calls be optimized out?

I was also reading http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx:

Empty destructors should not be used. When a class contains a destructor, an entry is created in the Finalize queue. When the destructor is called, the garbage collector is invoked to process the queue. If the destructor is empty, this just causes a needless loss of performance.

Does that mean that with an empty destructor, an entry is still created in the Finalize queue, but the JIT will prevent calling the method?

riQQ
  • 9,878
  • 7
  • 49
  • 66
Nelson Rothermel
  • 9,436
  • 8
  • 62
  • 81

3 Answers3

3

Normal empty methods (or other short methods like most getters and setters) are optimized by the JIT by inlining them in the compiled code: where a call to the method would normally appear, the whole body of the method is placed instead.

There are many cases where inlining is not worth it from performance perspective and so the compiler doesn't inline them, primarily when the method is longer than just few instructions.

There are some cases when inlining is not possible, like recursive or virtual methods. And since a finalizer (also known as destructor) is actually just overriden virtual method object.Finalize(), the compiler just can't inline it, so the method is actually called, even if it is empty.

But the performance hit from calling a method is tiny. The overhead required to process the finalizer by the GC is much bigger and so you shouldn't create classes with empty finalizers, regardless of inlining. This is the reason why you should use GC.SuppressFinalize() when implementing the Dispose pattern.

svick
  • 236,525
  • 50
  • 385
  • 514
2

It is not optimized away from the IL. I cannot speak for the Just-In-Time-compiled machine code.

I verified this by creating a small class, compiling it, then running ILDasm to look at the IL.

To verify whether it is put in the finalize queue you would need to do this:

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.
agent-j
  • 27,335
  • 5
  • 52
  • 79
  • 2
    Of course the are not optimized away in the IL. 99% of optimization happens in JIT, and this is what really matters. – Andrew Savinykh Jun 09 '11 at 22:08
  • 2
    AFAIK, no methods are optimized away by the C# compiler. For example, you wouldn't be able to call such method using reflection. – svick Jun 09 '11 at 22:25
1

Calling to the finalizer is not the same as calling to other methods. It is more akin to using a delegate. Effectively the JIT doesn't know enough about the destination to optimize out the method call, meaning that your method will be called and will simply return.

EDIT: Another point, whatever part of the CLR that calls your finalizer will be JITed once, which means there is not an opportunity to optimize for your particular case. Overall it is best to not add a finalizer unless you need it.

Guvante
  • 18,775
  • 1
  • 33
  • 64
  • How is it akin to using a delegate? Calling a finalizer is just calling a virtual method. It's just that C# doesn't allow you to do that. – svick Jun 09 '11 at 22:35
  • @svick: I was trying to think of an example where the JIT could not possibly know to remove it and it is what came to mind. Virtual method where the final type is the same situation I guess. – Guvante Jun 10 '11 at 04:14