我一直在读乌尔里希·德雷珀的书,“每个程序员都应该了解的内存知识 http://lwn.net/Articles/250967/“并在部分3.3.2 缓存效果的测量 http://lwn.net/Articles/252125/(页面中间)它给我的印象是访问结构体的任何成员都会导致整个结构体被拉入 CPU 缓存。
它是否正确?如果是这样,硬件如何知道这些结构的布局?或者编译器生成的代码是否以某种方式强制加载整个结构?
或者使用较大结构导致的速度减慢主要是由于结构分布在更多内存页上而导致 TLB 未命中?
Drepper 使用的示例结构是:
struct l {
struct l *n;
long int pad[NPAD];
};
Where sizeof(l)
是由NPAD
等于 0、7、15 或 31,导致结构体间隔 0、56、120 和 248 字节,并假设缓存行为 64 字节和 4k 页。
随着结构的增长,即使实际上除了指针之外没有其他任何东西被访问,仅仅迭代链表就会变得非常慢。
硬件根本不知道该结构。但确实,硬件在缓存中加载了您实际访问的字节周围的一些字节。这是因为缓存行有一个大小。它不适用于逐字节访问,但适用于例如一次 16 字节大小。
对结构体成员进行排序时必须小心,以便经常使用的成员彼此靠近。例如,如果您有以下结构:
struct S {
int foo;
char name[64];
int bar;
};
如果成员变量 foo 和 bar 经常使用,硬件将在缓存中加载 foo 周围的字节,当您访问 bar 时,它必须加载 bar 周围的字节。即使 foo 和 bar 周围的这些字节从未使用过。现在重写你的结构如下:
struct S {
int foo;
int bar;
char name[64];
};
当您使用 foo 时,硬件将在缓存中加载 foo 周围的字节。当您使用 bar 时,bar 已经在缓存中,因为 bar 包含在 foo 周围的字节中。 CPU 不必等待 bar 进入缓存。
答案是:访问单个结构体成员不会将整个结构体拉入缓存,而是将结构体的其他成员拉入缓存。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)