我有几个类遭受缓存争用,并使用“new”运算符进行分配。我可以以某种方式确保“new”返回一个与缓存行对齐的地址吗?
我正在使用GCC(如果不可能的话)。
答案 0 :(得分:3)
您可以分别对glibc或Windows CRT系统使用memalign
或_aligned_alloc
。你甚至可以使用像nedmalloc这样的自定义分配器并让它对齐块,这也可以为你提供一些额外的奖励。
你也应该用__attribute__((aligned(64)))
标记它们,以防它们被静态分配。
答案 1 :(得分:3)
解决此问题的最简单方法是使对象足够大,以至于无法共享缓存行。使用gcc你可以设置类的对齐方式(我假设你的对象小于高速缓存行,因为你遇到了争用):
class foo {} __attribute__((aligned(2 * CL)));
当然,您需要为CL
的架构插入正确的Cachelinesize(或者将其放入宏中并在那里使用)。我使用了两倍大小的缓存行,因为我记得new
并不能保证它实际上会确保对齐被保留。由于无法保证对象在高速缓存行的开头处开始,因此您仍然可以在同一个高速缓存行中获取不同对象的一部分(即一个对象的结尾和另一个对象的开头)。如果始终保留对象,__attribute__((aligned(CL)))
就可以了。当然,这需要你改变你的结构并浪费很多空间。
您还可以根据new
编写自己的memalign
(查看here了解如何执行此操作)。对于更多的bandaid解决方案,您还可以直接使用memalign
并使用placement new将对象放入分配的空间内。当然,这会使使用这些对象的代码变得不那么好。
答案 2 :(得分:1)
您可以使用placement new
将对象构造到给定的内存区域中:
// Instantiate object into a pre-allocated buffer
obj = new (buf) TheClass();
要获得对齐的缓冲区buf
,您可以使用memalign
,sbrk
或mmap
。