[英]How to design objects for performance
在最近读一本关于物理引擎开发的书时 ,我遇到了一个我以前从未考虑过的设计决策。 这与CPU处理内存中的原始字节的方式有关。
考虑以下课程:
class Foo
{
public:
float x;
float y;
float z;
/* Constructors and Methods */
private:
float padding;
}
作者声称填充,在x86架构中将对象的大小增加到四字,可以显着提高性能。 这是因为4个单词在内存中比3更干净 ,这是什么意思? 用冗余数据填充对象以提高性能对我来说似乎很矛盾。
这也引出了另一个问题,那些大小为1或2个单词的对象呢? 如果我的班级是这样的:
class Bar
{
public:
float x;
float y;
/* Constructors and Methods */
private:
/* padding ?? */
}
我应该在这个类中添加填充,以便它在内存中更干净地放置吗?
编译器有责任决定合理的填充(假设是典型的访问模式)。 编译器确实比你想象的更了解你的机器。 此外,你的机器将与你在一起几年; 该计划将持续数十年,在各种平台上运行,受到令人难以置信的各种使用模式的影响。 对于今天的i7来说,最好的是明天的i8或ARMv11。
为追求难以捉摸的“性能”而混淆的代码完全属于过早优化 。 永远记住你的时间(写作,测试,调试,一周后再次理解,调整代码)比可能浪费的计算机时间要贵得多(除非所说的代码每天在数百万台机器上运行数千次) , 那是)。 代码调整完全没有任何意义,直到你有足够的事实表明性能不够, 测量结果告诉你,改变这种结构是一个值得担心的瓶颈。
处理器并不像人类那样逐字节地“读取”存储器,它们按块处理块,可变大小取决于处理器。 它被称为内存访问粒度;
通过“内存对齐”您的对象,访问时间可能更快,您还可以避免数据碎片。
您可以在此处阅读有关数据对齐的更多信息
编辑:我不是说这是一个好的或坏的做法,只是分享我所知道的。
在回答这个问题时,有两个非常重要的事情要说。
首先,如果您要调整代码以获得性能优势,并且如果您认为值得(无论出于何种原因),您必须首先编写基准。 你必须能够尝试两者并衡量差异。
其次,这种调整将取决于汇编语言如何与硬件交互。 您必须能够阅读汇编语言代码并理解不同的指令集和硬件访问模式,以便了解这些调整可能起作用的原因。
最后,你的问题没有孤立的答案。 这取决于这些对象是单独分配还是集合; 他们旁边是否还有其他物品; 以及编译器如何为每种情况生成代码。 在所有可能的情况下,二次幂边界上的对齐将比未对齐更快,但是适合高速缓存的集合比不这样做的集合更快。 我不希望填充8或4字节来提高性能,但如果它很重要,我会尝试并测试结果。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.