前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >虚函数的性能真的那么差?

虚函数的性能真的那么差?

作者头像
高性能架构探索
发布2024-04-10 14:45:42
1310
发布2024-04-10 14:45:42
举报
文章被收录于专栏:技术随笔心得技术随笔心得

昨天在查阅某个问题的时候,突然看到了关于各个操作的性能损耗,今天就借助这篇文章,聊聊我们印象中性能很差的虚函数~~。

关于虚函数

对于虚函数(virtual function)的实现机制,在此就不再赘述了,本节我们聊聊关于虚函数的性能消耗这块。

下面且看一个例子:

代码语言:javascript
复制
class Base
{
public:
     void fun() {}
     virtual void vfun() {}
};

class Derived : public Base
{
public:
     void vfun() {}
};

void vfun(Base *b) {
  b->vfun();
}

void fun(Base *b) {
  b->fun();
}

emm,相信很多人看过Stanley B. Lippman的<<Inside the C++ Object Model>>一书,其中讲到,在编译器的实现机制中,非静态成员函数需要通过对象实例来调用,因为它们隐式地接收一个指向对象本身的this指针作为第一个参数。换句话说,就是编译器对成员函数的实现中,会将成员函数实现成为与普通函数一样,唯一的区别就是在函数参数末尾会增加一个隐式参数-this指针

那么,上面Base类中,fun()函数的实现,在编译器看来,可能如下:

代码语言:javascript
复制
M4BaseFvvE(Base * _this)

继续看下面这段代码:

代码语言:javascript
复制
int main() {
  Base *b1 = nullptr;
  Base *b2 = nullptr;
  b1 = new Base;
  b2 = new Derived;
  b1->vfun();
  b2->vfun();
}

在上述代码中,有两个Base类型的指针,分别指向基类Base和派生类Derived,那么其调用机制又如何呢?

首先,与非virtual函数实现机制一样,对于virtual函数,都会增加一个默认的指向实际对象的this指针。

其次,编译器在包含虚函数的类中添加一个隐含的指针vptr指向类的虚函数表,一般情况下,这个vptr指针在对象的最前面

最后,在运行时,通过查找虚函数表,进而找到正确的应该被调用的函数。

也就是说,对于虚函数的调用,最终,编译器可能会变成:

代码语言:javascript
复制
(*b1->vptr[i])(p); // p为实际对象的地址,即Base对象
(*b1->vptr[i])(p); // p为实际对象的地址,即Derived对象

好了,上述这个过程仅仅是本文的后续内容的一个铺垫,往往,我们说虚函数性能差,是因为虚表的查找过程导致性能较普通函数或者普通成员函数查,嗯,相信很多人和我一样,认为这个差,是很差~~

性能

直到我昨天在查阅某个问题的时候,恰好看了一张各种操作的性能分析图,算是颠覆了之前的某些认知。

好了,图来了~~

从上图可以看出,我们所理解的虚函数性能(准确的说是查虚表)的性能,与L3差不多,整数除法操作的一半性能。

基于上图,可以看下代码中哪些地方可以优化,当然了,可以从底部开始(如果非要从顶部开始的话,也没人拦着~),如果非要总结的话,那就如下几点:

•一次IO毁所有•多线程只是可选,如果单线程能完成且性能不错的前提下,慎用多线程,毕竟其上下文切换开销很大•异常处理的性能损耗超过我们想象•尽量避免系统/内核调用

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-04-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 高性能架构探索 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 关于虚函数
  • 性能
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档