Files
Inbox/小技术/跨缓存行(Cache Line Split).md
2025-12-11 07:24:36 +08:00

2.8 KiB
Raw Permalink Blame History

tags, aliases, date created, date modified
tags aliases date created date modified
1. 宏观原理图:箱子与积木的错位
星期一, 十一月 24日 2025, 5:50:26 下午 星期一, 十一月 24日 2025, 5:50:35 下午

1. 宏观原理图:箱子与积木的错位

想象 CPU 是一个强迫症收纳师,他手里有一排固定的收纳盒(缓存行),每个盒子长度固定是 64。

我们要存的数据(点迹) 是长度为 48 的积木条。

请看下面的图,展示了当我们把积木一条接一条紧挨着放进去时,发生了什么:

---
config:
    theme: base
    flowchart:
        curve: linear
---
graph LR
    %% 样式定义
    classDef box fill:#e6f7ff,stroke:#1890ff,stroke-width:2px,stroke-dasharray: 5 5
    classDef block1 fill:#ffccc7,stroke:#f5222d,stroke-width:2px
    classDef block2 fill:#d9f7be,stroke:#52c41a,stroke-width:2px

    subgraph Memory["内存空间 (连续摆放)"]
        direction LR
        
        subgraph Box1["收纳盒 1 (容量 64)"]
            direction LR
            A1["积木A (48)"]:::block1
            B1["积木B 的头 (16)"]:::block2
        end
        
        subgraph Box2["收纳盒 2 (容量 64)"]
            direction LR
            B2["积木B 的身子 (32)"]:::block2
            C1["…"]:::white
        end
    end

    %% 解释连接
    A1 -- 紧挨着 --> B1
    B1 -- "⚠️ 惨遭腰斩 ⚠️" --> B2

2. 细节文字表述:为什么这很糟糕?

场景还原:

  1. 强迫症规则CPU 每次读取数据,必须连盒带盖端走整整一个“收纳盒”64 字节),不能只捏走里面的某一块。

  2. 读取积木 A红色

    • CPU 伸手端走 收纳盒 1
    • 积木 A 完整地在盒子里。
    • 耗时1 次搬运。(快)
  3. 读取积木 B绿色

    • CPU 端走 收纳盒 1,拿到了积木 B 的
    • CPU 发现身子没了,只能再去端走 收纳盒 2,拿到积木 B 的身子
    • 然后 CPU 还得在手里把这两段拼起来。
    • 耗时2 次搬运 + 拼接时间。(慢!)

3. 结论与解决方案

  • 问题核心因为数据的尺寸48不能被盒子的尺寸64整除导致后续的数据像“跨栏”一样骑在两个盒子的边界上。这叫跨缓存行Cache Line Split
  • 我们的方案(填充 Padding
    • 既然 48 放不进 64 很尴尬,我们就在每个积木后面硬塞 16 块没用的泡沫Padding
    • 把积木强行撑大到 64
    • 结果虽然浪费了空间但现在每个盒子正好放一个积木。CPU 拿任何积木都只需要搬 1 次盒子。

这就是我们为了极致性能所做的妥协:用空间换时间