缓存未命中

缓存未命中(Cache Miss) 发生在 CPU 访问某块内存时,该地址不在当前缓存(L1/L2/L3)中,导致程序被迫从更慢的内存(RAM)读取数据,严重拖慢程序执行速度。

📍 一、什么时候会发生缓存未命中?

常见原因包括:

场景 说明

❌ 数据访问不连续 比如访问数组跳着取(a[i*10])导致预取失败

❌ 频繁访问大量数据 比如一个 10GB 数组,超出缓存容量(一般几十KB ~ MB)

❌ 使用指针结构(如链表)遍历 每个节点不连续,CPU 无法预取

❌ 跨线程竞争同一缓存行(称为 false sharing) 多线程操作挨得太近的数据

❌ 数据结构嵌套复杂 多层嵌套对象,内存分布分散

❌ 随机访问容器(如 unordered_map) 哈希表节点可能分散,跳来跳去访问内存

❌ 示例:跳跃访问数组(坏的局部性)

❌ 示例:链表遍历

如何减少

✅ 1. 连续内存访问(改善局部性)

✅ 2. 结构体内存对齐优化

✅ 3. 数组替代链表

✅ 4. 减少内存分配碎片

✅ 5. 利用预取机制(CPU会自动做,但你可帮它)

✅ 6. 结构体压缩布局(小对象数组压缩)

✅ 7. 多线程注意缓存行对齐

✅ 避免 false sharing

结构体压缩布局的思想:

复制代码
不要这样:
std::vector<std::unique_ptr<Node>> nodes;
会导致数据四分五裂,缓存命中率差。

应该这样:

struct Node { int x, y; };
std::vector<Node> nodes;


// 所有数据连续,命中率高!

✅ 简单解释:

这个建议的核心是 数据布局 与 缓存命中率 的关系。

🧠 你代码是干嘛的?
不推荐的写法:
std::vector<std::unique_ptr<Node>> nodes;


你创建了一个 vector 容器,里面放的是 指向 Node 的智能指针。

每个 Node 是单独在堆上分配的内存(用 new 出来的)。

所以,内存长这样:

[nodes vector] ---> [ptr1] --> [Node1 在堆上]
                   [ptr2] --> [Node2 在堆上]
                   [ptr3] --> [Node3 在堆上]


这些 Node 是分散在内存中的。

如果你遍历 nodes,访问每个 Node,由于它们位置不连续,CPU 缓存命中率差,性能低。

推荐的写法:
struct Node { int x, y; };
std::vector<Node> nodes;


你创建了一个 vector<Node>。

每个 Node 是直接在 vector 的内部内存块中分配的,是 连续排列的!

内存结构大概是这样的:

[nodes vector 内存] --> [Node1][Node2][Node3](连续)


当你遍历这个 vector 的时候,CPU 能一次性加载多个 Node 进缓存,命中率高,性能好。

📌 总结:为啥推荐第二种写法?
项目	vector<unique_ptr<Node>>	vector<Node>
内存布局	分散在堆上	连续在内存中
CPU 缓存命中率	差	高
遍历性能	差	高
适用场景	Node 很大或多态(虚函数)时才需要	Node 很小且无继承时最好用这个
⚠️ 补充说明:

如果 Node 是一个 抽象基类或有复杂资源管理(如虚函数、继承、变长数据) 的结构,那你可能不得不用 unique_ptr<Node>。

但如果 Node 是个简单的数据结构,比如 int x, y; 这种,就尽量用 值类型(vector<Node>),性能会更好。
相关推荐
虫小宝2 小时前
返利app排行榜的缓存更新策略:基于过期时间与主动更新的混合方案
java·spring·缓存
Light602 小时前
领码SPARK融合平台 · TS × Java 双向契约 —— 性能与治理篇|缓存分段与版本秩序
低代码·缓存·spark
bikong72 小时前
桥接模式,打造灵活可扩展的日志系统C++
c++·桥接模式
艾莉丝努力练剑2 小时前
【C++】类和对象(下):初始化列表、类型转换、Static、友元、内部类、匿名对象/有名对象、优化
linux·运维·c++·经验分享
疋瓞3 小时前
C++_STL和数据结构《1》_STL、STL_迭代器、c++中的模版、STL_vecto、列表初始化、三个算法、链表
数据结构·c++·算法
三体世界3 小时前
测试用例全解析:从入门到精通(1)
linux·c语言·c++·python·功能测试·测试用例·测试覆盖率
Bear on Toilet3 小时前
继承类模板:函数未在模板定义上下文中声明,只能通过实例化上下文中参数相关的查找找到
开发语言·javascript·c++·算法·继承
Java烘焙师4 小时前
架构师必备:缓存更新模式总结
mysql·缓存
努力努力再努力wz4 小时前
【c++进阶系列】:map和set的模拟实现(附模拟实现的源码)
java·linux·运维·开发语言·c++