You often hear/read that one of the reasons why C# methods aren’t virtual by default is because of performance. Calling a virtual method is more expensive than calling a regular instance method, because the CLR has to determine the correct override to call at runtime, instead of being able to simply call the instance method directly. Another reason why virtual methods are more expensive to call is because they can never be inlined.
Is it really that much more expensive though? I ran a little experiment and i’d like to share the results with you.
Suppose you have the following 2 classes:
public class MyClass
{
protected long someLong;
public void IncreaseLong()
{
someLong++;
}
public virtual void VirtualIncreaseLong()
{
someLong++;
}
}
public class MyDerivedClass : MyClass
{
public override void VirtualIncreaseLong()
{
someLong += 2;
}
}
As you can see, there is no difference between the IncreaseLong and VirtualIncreaseLong methods, except that the latter is virtual and the former is a regular instance method. According to many people, calling VirtualIncreaseLong instead of IncreaseLong will be more expensive. I also have a derived class which overrides the VirtualIncreaseLong method with a slightly different implementation.
If we call these methods a bunch of times (like 1000000000 times), we should notice quite a difference according to many people.
I wrote the following test code which calls these methods a bunch of times, times it, and outputs the results.
class Program
{
const int numberOfTimes = 1000000000;
static void Main(string[] args)
{
var myObject = new MyClass();
var myDerivedObject = new MyDerivedClass();
// we do this so there's no first-time performance cost while timing
EnsureThatEverythingHasBeenJitted(myObject);
EnsureThatEverythingHasBeenJitted(myDerivedObject);
TestNormalIncreaseMethod(myObject);
TestVirtualIncreaseMethod(myObject);
TestNormalIncreaseMethod(myDerivedObject);
TestVirtualIncreaseMethod(myDerivedObject);
Console.ReadLine();
}
static void EnsureThatEverythingHasBeenJitted(MyClass theObject)
{
theObject.IncreaseLong();
theObject.VirtualIncreaseLong();
}
static void TestNormalIncreaseMethod(MyClass theObject)
{
Console.WriteLine(string.Format("calling the IncreaseLong method of type {0} {1} times", theObject.GetType().Name, numberOfTimes));
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < numberOfTimes; i++)
{
theObject.IncreaseLong();
}
stopwatch.Stop();
Console.WriteLine("Elapsed milliseconds: " + stopwatch.ElapsedMilliseconds);
}
static void TestVirtualIncreaseMethod(MyClass theObject)
{
Console.WriteLine(string.Format("calling the VirtualIncreaseLong method of type {0} {1} times", theObject.GetType().Name, numberOfTimes));
var stopwatch = Stopwatch.StartNew();
for (var i = 0; i < numberOfTimes; i++)
{
theObject.VirtualIncreaseLong();
}
stopwatch.Stop();
Console.WriteLine("Elapsed milliseconds: " + stopwatch.ElapsedMilliseconds);
}
}
The output of running this code might surprise you. On my machine, i got the following results when the code was compiled in debug mode:
The difference between calling the regular instance method and the virtual method is quite small. I’d even say it’s negligible.
When compiling in release mode, i got the following output:
I ran the test a bunch of times, and there was no consistent observable performance penalty when calling the virtual methods. In fact, the virtual methods often performed faster than the regular instance methods and in most cases were equally fast. I’m not claiming that virtual methods are faster than regular instance methods, but if there really was an extra real-world performance cost associated with virtual methods, it surely should be observable with this test code, no?
Obviously, this test isn’t scientific in any way. But still, i think it does show that the so called performance cost associated with virtual methods is highly overrated. There definitely will be cases where virtual methods are more expensive than regular instance methods, but i’m willing to bet that those cases are rare and that the vast majority of .NET developers will never be negatively impacted by it.
Side note: have you ever noticed that most people who recommend to avoid virtual methods due to their performance cost never put the same emphasis on avoiding the cost of say, frequent remote operations? Which is odd, since i wouldn’t be surprised if that would be the most common reason for performance problems with .NET applications. Then again, that’s what you get when the biggest company pushing a platform advocates meaningless performance improvements while at the same time pushing bad architectural decisions/guidelines on the world because the resulting code is supposedly easier to write, use and maintain.
You can download the example code here so you can run the test yourself.
Pingback: The Morning Brew - Chris Alcock » The Morning Brew #514
Pingback: Interesting Finds: 2010 01.10 ~ 01.18 - gOODiDEA.NET
Pingback: Virtual Method Performance Penalty, Revisited | The Inquisitive Coder – Davy Brion's Blog