Apollo 技术文档Apollo 技术文档
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
指南
  • 架构概述
  • BigWorld 架构深度解析
  • BigWorld 进程架构与玩家生命周期
  • AOI九宫格系统详解
  • AOI广播与消息去重
  • Base 模块
  • Core 模块
  • Runtime 模块
  • Data 模块
  • Network 模块
  • /modules/actor.html
  • Game 模块
  • BigWorld 模块
服务器应用
API 参考
QA
GitHub
  • MMORPG 架构 QA

Q65: 如何减少 CPU 缓存未命中?

核心结论

减少 cache miss 的关键,不是记住缓存层级参数,而是让程序访问数据的方式更连续、更可预测、更少跨核抖动。

真正最值得关注的是:

  • 数据布局
  • 访问顺序
  • 指针跳转
  • 共享写入

如果这些不改,只靠对齐和小修小补,收益通常有限。

一、为什么 cache miss 值得重视

CPU 远比内存快得多。

所以性能问题常常不是“算得太慢”,而是:

  • 数据拿不到
  • 拿得太散
  • 线程互相打架把缓存刷掉

这在高频遍历、实体更新、消息处理这类路径里尤其明显。

二、最常见的 miss 来源

1. 指针追逐

例如对象层层嵌套、链表过多、碎片化严重。

2. 数据布局差

热字段和冷字段混在一起,导致每次都拉进很多没用数据。

3. 访问顺序差

遍历顺序和内存布局不匹配,会让缓存利用率很差。

4. 伪共享和跨核写入

不同线程频繁写同一 cache line,会导致缓存来回失效。

三、最有效的优化通常从数据布局开始

常见做法包括:

  • 把热字段放在一起
  • 冷字段拆出去
  • 减少对象层级
  • 用连续容器代替零散节点

这比单纯调整编译参数更有效。

四、访问模式比单个对象大小更重要

同样一份数据,如果按顺序扫描,和随机跳着访问,性能可能差很多。

所以设计时要注意:

  • 能否批量顺序遍历
  • 能否按处理阶段重排数据
  • 能否减少跨结构来回跳转

五、多线程下要注意共享写入

有些 cache miss 并不是单线程布局问题,而是线程之间互相把缓存行打散。

常见场景包括:

  • 全局计数器
  • 共享队列头尾
  • 紧邻字段被不同线程写

这时就要考虑:

  • 分片
  • 本地缓冲
  • padding
  • 减少共享写路径

六、为什么数据导向设计常常有效

因为它强调:

  • 把一起访问的数据放一起
  • 按批次处理相同逻辑
  • 尽量减少无关字段参与热路径

这和减少 cache miss 的目标天然一致。

七、工程上更稳妥的优化顺序

常见做法是:

  1. 先用 profiling 找高 miss 热点
  2. 先看数据结构和访问顺序
  3. 再考虑对齐、padding 和更细节的 cache line 调整

否则很容易做很多低收益微优化。

八、常见误区

1. cache miss 只是底层细节,不值得管

在高频热路径里,它往往就是核心瓶颈。

2. 用链表比数组灵活,所以没关系

灵活不等于高效,链表和分散对象很容易制造指针追逐。

3. 只要对象变小,cache miss 就会变少

不一定。访问顺序和共享模式同样重要。

参考资料

  • Data-Oriented Design、cache locality 与 false sharing 相关资料
在 GitHub 上编辑此页
最后更新: 3/20/26, 6:06 AM
贡献者: cuihairu