Question is as stated in the title: What are the performance implications of marking methods / properties as virtual?
Note - I'm assuming the virtual methods will not be overloaded in the common case; I'll usually be working with the base class here.
The main advantage of virtual functions are that they directly support object oriented programming. When you declare a function as virtual you're saying that exactly what code is executed depends on the type of the object you call it against. you can't tell exactly what code path it's going to follow.
A virtual method is one that is declared as virtual in the base class. A method is declared as virtual by specifying the keyword "virtual" in the method signature. A virtual method may or may not have a return type. Virtual methods allow subclasses of the type to override the method.
Virtual functions are by definition slower than their non-virtual counterparts; we wanted to measure the performance gains from inlining; using virtual functions would make the difference even more pronounced.
Static methods are 6 times faster than normal instance methods. Static methods are 68 times faster than virtual methods. Virtual methods are 10.5 times slower than instance methods. Makes you think to carefully choose which methods should be virtual.
Virtual functions only have a very small performance overhead compared to direct calls. At a low level, you're basically looking at an array lookup to get a function pointer, and then a call via a function pointer. Modern CPUs can even predict indirect function calls reasonably well in their branch predictors, so they generally won't hurt modern CPU pipelines too badly. At the assembly level, a virtual function call translates to something like the following, where I
is an arbitrary immediate value.
MOV EAX, [EBP + I] ; Move pointer to class instance into register MOV EBX, [EAX] ; Move vtbl pointer into register. CALL [EBX + I] ; Call function
Vs. the following for a direct function call:
CALL I ; Call function directly
The real overhead comes in that virtual functions can't be inlined, for the most part. (They can be in JIT languages if the VM realizes they're always going to the same address anyhow.) Besides the speedup you get from inlining itself, inlining enables several other optimizations such as constant folding, because the caller can know how the callee works internally. For functions that are large enough not to be inlined anyhow, the performance hit will likely be negligible. For very small functions that might be inlined, that's when you need to be careful about virtual functions.
Edit: Another thing to keep in mind is that all programs require flow control, and this is never free. What would replace your virtual function? A switch statement? A series of if statements? These are still branches that may be unpredictable. Furthermore, given an N-way branch, a series of if statements will find the proper path in O(N), while a virtual function will find it in O(1). The switch statement may be O(N) or O(1) depending on whether it is optimized to a jump table.
Rico Mariani outlines issues regarding performance in his Performance Tidbits blog, where he stated:
Virtual Methods: Are you using virtual methods when direct calls would do? Many times people go with virtual methods to allow for future extensibility. Extensibility is a good thing but it does come at a price – make sure your full extensibility story is worked out and that your use of virtual functions is actually going to get you to where you need to be. For instance, sometimes people think through the call site issues but then don’t consider how the “extended” objects are going to be created. Later they realize that (most of) the virtual functions didn’t help at all and they needed an entirely different model to get the “extended” objects into the system.
Sealing: Sealing can be a way of limiting the polymorphism of your class to just those sites where polymorphism is needed. If you will fully control the type then sealing can be a great thing for performance as it enables direct calls and inlining.
Basically the argument against virtual methods is that it disallows the code to be a candidate of in-lining, as opposed to direct calls.
In the MSDN article Improving .NET Application Performance and Scalability, this is further expounded:
Consider the Tradeoffs of Virtual Members
Use virtual members to provide extensibility. If you do not need to extend your class design, avoid virtual members because they are more expensive to call due to a virtual table lookup and they defeat certain run-time performance optimizations. For example, virtual members cannot be inlined by the compiler. Additionally, when you allow subtyping, you actually present a very complex contract to consumers and you inevitably end up with versioning problems when you attempt to upgrade your class in the future.
A criticism of the above, however, comes from the TDD/BDD camp (who wants methods defaulting to virtual) arguing that the performance impact is negligible anyway, especially as we get access to much faster machines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With