看了 C++ 的虚函数的一些文章,对于其性能消耗的优化思路整理了一下。
1、开销
对于虚函数,编译器可以通过关键字 virtual
识别,并为它们创建虚表,虚表保存着指向函数地址的信息。当一个具有虚函数的对象(object) 被创建时,编译器也会为它创建指向虚表的虚指针。
所以要访问到对应的虚函数,每次执行需要先解引用虚指针,偏移到虚表对应函数位置,然后调用。虚函数的开销主要体现在:
- 由于这个操作需要在运行时完成,所以虚函数没法像普通函数一样被 inline,同时也就失去了一些优化机会(inline 后可以进行更多的优化,如常量传播)。
- 现代 CPU 在进行分支跳转前会进行分支预测,对于虚函数而言,硬件在很晚的时机才会知晓要跳转的位置,这可能会导致存在分支预测失败的额外开销。
- 多次调用不同实现的相同符号的虚函数,对 cache 不友好。
根据性能测试结果,给出了以下建议:
- 合理安排对象的内存位置。带来更好的局部性。
- 尝试把一些小的函数脱虚(变成普通函数调用一样)。小函数的调用开销比执行更高。
- 把数组里的对象先按类型排好序。这样对 cache 会更友好。