考虑到具有新的移动指令和新内存控制器的新CPU,如果在C++中有一个Derived对象向量,其中Derived是由虚拟成员函数组成的,那么这对本地来说是好事还是坏事呢?
如果我有一个指向基类Base*的指针向量,在该向量中存储从Base到1-2-3级别的派生对象的引用,该怎么办?
基本上,动态类型适用于这两种情况,但哪一种更适合缓存和内存访问?
我倾向于这两种观点,但我希望看到关于这一问题的完整答案。
在过去的2-3年里,有新的东西可以被认为是硬件行业的地面制动吗?
发布于 2013-08-07 16:40:46
在向量中存储Derived而不是Base *更好,因为它消除了一个额外的间接方向,并且将所有对象放置在一个连续内存中,这反过来又使硬件预取器的工作更容易,有助于分页、TLB丢失等等。但是,如果这样做,请确保不引入切片问题。
至于这种情况下的虚拟分派,除了此指针所需的调整之外,几乎没有关系。例如,如果Derived重写正在调用的虚拟函数,并且已经有指向Devied *的指针,则不需要进行此调整,否则应该将其调整为基类的此值之一(这也取决于继承层次结构中类的大小)。
只要向量中的所有类都有相同的重载,CPU就能够预测发生了什么。但是,如果您有不同的实现组合,那么CPU将不知道将为每个下一个对象调用什么功能,这可能会导致性能问题。
别忘了在你做出改变之前和之后都要分析一下。
发布于 2013-08-07 16:44:44
现代CPU知道如何优化数据依赖的跳转指令,也知道如何对数据依赖的“分支”指令进行优化--处理器将“了解”“上一次我通过这里,我走了这条路”,如果它有足够的信心(经历了几次同样的结果),它就不会继续这样做。
当然,如果实例是不同类的完全随机选择,并且每个类都有自己的虚拟函数,那就没有帮助了。
当然,缓存-局部性是一个稍微不同的问题,这实际上取决于您是在存储对象实例,还是在向量中存储指向实例的指针/引用。
当然,一个重要的因素是“选择是什么?”--如果您使用的是“正确”的虚拟函数,这意味着(至少)在代码路径中有一个条件检查(至少),因为这个决定是在更早的阶段作出的。如果您用其他方法求解决策的分支概率(假设概率对应于相同的概率)--这至少对性能的影响与virtual函数的概率相同(很可能更糟,因为我们现在有了一个if (x) foo(); else bar();类型的场景,所以我们首先必须计算x,然后选择路径。obj->vfunc()将是不可预测的,因为获取vtable会产生一个不可预测的结果--但至少vtable本身是缓存的。
https://stackoverflow.com/questions/18108718
复制相似问题