Often, we developers do not realize the pros and cons of a feature in a language. Yet we still do use them according to our whims and fancies. Although at first you might think I am talking non-sense, any good programmer should also think twice about a feature before accepting it for granted.
In this article, I will talk about Virtual Methods in inheritance trees causing performance overheads sometimes or when used extensively.
Even though you can place the override
keyword in every method, internally the compiler converts all of them to virtual
. Hence at run time, the CLR has to execute one more instruction and has to look in method tables as which concrete types method has to be called. This extra calculation or searching pattern does add a bit of performance hit (thanks to Qwertie for pointing the mistake), if it is done often by the CLR. Hence the virtual methods do not get inlined by the compiler.
Let's see some sample code:
As you can see from the above code, although it looks very simplistic in nature, there is a small trick to this article's interests.
Let's see the main method's IL:
As you can see from the IL, in comparison with the Main()
code, I have declared:
SecondChild d = new ThirdChild()
But in the IL, the compiler is calling virtually Base.DoWork()
. Since the run time sees the virtual
keyword in the method definition, it tries to search the hierarchy in the child classes from this base class. This way it traverses till the leaf node in the tree till it no longer finds the overriding method/in other words, another virtual method at least in this example. Otherwise, it will traverse till the RHS class encountered which is declared in the code, i.e., ThirdChild()
here. Beyond that, it does not care to search, since that’s how it has been declared in the code.
In the above case, since the method in the ThirdChild
class has a new definition, it hooks up the call for SecondChilds DoWork()
. If you remove the new
keyword from the ThirdChild
class DoWork()
, and provide the override
keyword, then the ThirdChild
class method shall be called. Since it is the most derived method available in the inheritance tree.
Now you might have understood how CLR runs through the whole long subclass tree structure. Hence it is better to avoid too many virtual
methods in your production code, folks.
Thanks for reading!
P.S.: Your valuable comments/votes are well appreciated.
Update
One of the CodeProject readers has requested me to provide a cost comparison. I wonder why I did not care/missed out to provide this information when I wrote the article. I apologize to all the readers for this mistake. So here I am providing the requested information:
So for test purposes, I wrote the following code: (Thanks Qwertie for pointing out the mistake.)
class Base
{
public virtual void Hello() { }
}
class Child1 : Base
{
public override void Hello() { }
}
class Child2 : Child1
{
public override void Hello() { }
}
class Child3 : Child2
{
public override void Hello() { }
}
class SomeClass
{
public void Hello() { }
}
sealed class Program
{
static void Main(string[] args)
{
Base b = new Child3();
Stopwatch sp = Stopwatch.StartNew();
b.Hello();
sp.Stop();
Console.WriteLine(sp.ElapsedTicks);
SomeClass c = new SomeClass();
sp = Stopwatch.StartNew();
c.Hello();
sp.Stop();
Console.WriteLine(sp.ElapsedTicks);
Console.ReadLine();
}}
Now as per this code, the output you get in terms of ticks shows you the performance or inheritance call ticks is more than directly calling a method. The output is shown below:
144873
141984
Yes the difference is very less, but upon increasing the hierarchy as well as frequent usage, this difference grows. Even I checked JR book on the same and it's true.
One more point worth mentioning here is, not only the virtual methods' performance is slow, it also depends on how we use it. Thanks to Kabwla suggestion that even using the inheritance tree does matter in performance issue, i.e., new usage over inheritance tree structure.
What I mean is, in the above test code in place of SomeClass c = new SomeClass()
if I had placed Child4 c = new Child4()
, then the performance of this would be very less even though Child4
is in the inheritance tree plus its method is a virtual
method. But run time gets smart in knowing it's not a cast to base type as in Base b = new Child4()
and hence it directly places a call. But most of the developers do not use child class instance directly, i.e., Child4 c = new Child4()
, so I can broadly say virtual inheritance is costly.