06. 提高缓存命中率

1.缓存行和局部性原理

2.提高缓存命中率策略


1.缓存行和局部性原理

csharp 复制代码
CPU缓存的最小存储单位是缓存行(Cache Line), 常见大小为64字节; 当CPU从内存读取数据时, 不会只读取目标字节, 而是

会把目标数据所在的整个缓存行(64字节)都加载到缓存中

a.空间局部性: 如果程序接下来要访问的数据和当前数据在内存中是连续的, 那么这些数据已经被加载到缓存里,直接读取即

可(缓存命中)

b.时间局部性: 如果程序在短时间内重复访问同一数据, 该数据会一直留在缓存中, 避免重复从内存读取

这两个局部性原理, 是所有缓存优化策略的基础

2.提高缓存命中率

csharp 复制代码
a.利用空间局部性: 让频繁访问的数据紧凑排列; 核心是"让高频访问的数据在内存中连续存储, 最大化缓存行的利用率"

- 正面例子: 遍历数组

数组是连续内存布局, 遍历数组时, CPU加载一个缓存行就能包含多个数组元素; 比如: 64字节的缓存行, 能装下16个int类

型元素(每个int4 字节); 遍历到第1个元素时, 后续15个元素已经在缓存里了, 命中率接近100%

- 反面例子: 遍历链表

链表的节点是分散内存布局(每个节点的next指针指向随机内存地址), 每次访问下一个节点都要去内存寻址,缓存行只能装一

个节点, 命中率极低

csharp 复制代码
b.利用时间局部性: 让高频数据常驻缓存; 核心是"减少高频数据的缓存驱逐, 让它在缓存里待得更久"

核心手段减少循环内的内存读写, 把循环中需要重复访问的变量, 缓存到局部变量中; 局部变量默认会被分配到CPU的寄存器

或L1缓存中, 访问速度极快

csharp 复制代码
c.避免"伪共享": 别让多线程破坏缓存行

这是多线程编程中容易踩的坑, 也是Unity C#多线程优化的关键

伪共享的本质: 多个线程同时修改同一个缓存行里的不同数据, 会导致缓存行频繁失效(缓存颠簸)

比如两个线程分别修改一个结构体的两个成员, 而这两个成员刚好在同一个缓存行: 线程A修改后, 缓存行标记为脏数据, 线

程B读取时发现缓存行失效, 必须重新从内存加载, 命中率直接归零
csharp 复制代码
现代CPU都是多核的(比如: 4核、8 核), 每个核心都有自己独立的L1、L2缓存, L3缓存是多核共享的; 为了保证所有核心读

取的数据是"一致的"(比如核心 1 修改了某个数据,核心 2 必须看到最新值,不能读旧数据), CPU有一套缓存一致性协议

最常见的是MESI协议, 这个协议有个关键规则: 当某个核心修改了自己缓存中的某个缓存行后, 会立即通知其他所有核心:你

们缓存里的这个缓存行已经失效了, 不能再用了; 其他核心如果后续要访问这个缓存行的数据,必须重新从内存或共享L3缓存

加载最新版本; 这就是伪共享的祸根 ------ 不是数据本身冲突, 而是缓存行被共用, 导致无辜的连带失效
csharp 复制代码
解决方法: 缓存行填充, 通过添加填充字节, 让每个线程操作的数据独占一个缓存行, 避免互相干扰
相关推荐
程序员鱼皮2 天前
女友怒骂国内不能用Claude Code,于是我给她做了一个
计算机·ai·程序员·大模型·互联网·编程
驱动探索者3 天前
[缩略语大全]之[编译器]篇
计算机·状态模式·飞书·编译器
驱动探索者3 天前
[缩略语大全]之[计算机图形学]篇
计算机·显示器·图形学·显示
程序员鱼皮4 天前
突发,快手被色情直播刷屏!背后的原因竟然是?
计算机·程序员·互联网·编程·事故
梁辰兴4 天前
计算机网络基础:以太网的 MAC 层
网络·计算机网络·macos·计算机·mac·以太网·梁辰兴
程序员鱼皮5 天前
从夯到拉,锐评 28 个后端技术!
后端·计算机·程序员·开发·编程经验
梁辰兴5 天前
计算机网络基础:局域网的数据链路层
网络·网络协议·计算机网络·计算机·数据链路层·局域网·梁辰兴
梁辰兴5 天前
计算机网络基础:以太网的信道利用率
服务器·网络·计算机网络·计算机·以太网·信道利用率·梁辰兴
躺柒6 天前
读人机沟通法则:理解数字世界的设计与形成01机器循环运行
人工智能·计算机·计算·数字世界·人机对话