缓存友好代码的核心是提升CPU对高速缓存的利用率,关键在于数据布局与访问模式匹配硬件特性:注重局部性、对齐、预取友好及避免伪共享;优先使用连续结构如vector而非链表,合理设计结构体大小与成员顺序,并确保顺序访问与缓存行对齐。

缓存友好代码的核心是让CPU更少地等待内存数据,更多地利用高速缓存(L1/L2/L3)。关键不是“写得快”,而是让数据布局和访问模式匹配硬件缓存行为:局部性(时间+空间)、对齐、预取友好、避免伪共享。
用连续内存布局替代指针跳转
链表、树等动态结构常导致随机访问和缓存行失效。数组、vector、结构体数组(SoA)或结构体内的数组(AoS)更易被预取器识别,提升空间局部性。
- 优先用
std::vector而非std::list存储同类型元素 - 处理多个相关字段时,考虑结构体数组(
struct Point { float x,y,z; }; std::vector),而非分离的坐标数组(x[], y[], z[]),除非有SIMD向量化需求pts; - 若需频繁按字段遍历(如只处理所有x),可权衡使用SoA(
struct Points { std::vector),但注意访问跨度仍应尽量小x, y, z; };
控制结构体大小与成员对齐
过大的结构体容易跨缓存行(通常64字节),一次加载浪费带宽;未对齐或填充过多会降低密度,减少每行容纳的元素数。
- 用
alignas(64)强制对齐到缓存行边界(适用于热点结构体或数组首元素) - 按大小降序排列成员(
double,int,char),减少编译器填充;必要时用[[no_unique_address]]或位域压缩小字段 - 用
static_assert(sizeof(MyStruct) 做编译期检查
顺序访问 + 合理步长
CPU预取器擅长识别固定步长的顺序读写。跳跃式、逆序、散列索引访问会使其失效。
立即学习“C++免费学习笔记(深入)”;
- 遍历二维数组时,确保内层循环沿连续内存方向(C风格:
for (int i = 0; i ,而非a[j][i]) - 避免在热循环中用模运算或复杂函数计算索引(如
arr[(i * prime) % size]),这破坏可预测性 - 若必须随机访问,考虑分块(blocking / tiling):把大问题拆成能装进L1缓存的小块,提高块内局部性
避免伪共享(False Sharing)
多个线程修改同一缓存行的不同变量,会导致该行在核间反复无效化,严重拖慢并发性能。
- 用
alignas(64)将高频更新的变量隔离到独立缓存行(尤其在线程局部计数器、锁状态等场景) - 不要把两个线程各自写的bool放在同一个struct里;宁可加padding,也不共用缓存行
- 使用
std::atomic时注意其实现是否隐含缓存行对齐(如gcc/clang下std::atomic通常不自动对齐,需手动处理)











