【问题标题】:How much of a "large" object gets brought in to the cache?有多少“大”对象被带入缓存?
【发布时间】:2014-07-05 12:27:03
【问题描述】:

如果我有一个包含多个大向量的对象,如果我访问其中一个向量数据成员,是否意味着其他向量(我没有访问过)也被带入缓存(可能通过空间局部性规则代码)?

如果我有:

class A{
    float p;
    int x[10000];
    int y[10000];
};

而我只是在一段特定的代码中访问p,访问A::p 对缓存的污染比

class B{
    float p;
    int x[10000];
    double y;
};

因为B 只有一个大数组,因此更小。

我的直觉是只加载经常访问的缓存行,而不是整个对象。

【问题讨论】:

  • 缓存行为取决于机器。如果您加载一块内存,则周围的内存也可能会被缓存,但是被缓存的内存大小与您的结构的外观无关,因为您的机器不知道结构是什么并且不在乎你认为它的成员属于一起。
  • 高速缓存行有一定的大小——可能是 128 字节。如果必须访问该行中的任何字节,则引入整行(甚至是不相关对象中的字节)。在最简单的缓存方案中,在引用之前不会引入额外的字节。
  • 只是评论:您在谈论向量,但您的示例使用 c 数组。这对答案没有影响,但就内存布局而言,这是完全不同的两件事。向量在堆上的单独内存区域管理它们的内存,而 c 数组的变量实际上是在对象内存区域内分配的。

标签: c++ performance caching cpu cpu-architecture


【解决方案1】:

无论对象如何,都会加载与您读取的地址相对应的缓存行。

这取决于您的平台。对于 64 字节的缓存行(即 8 或 16 个整数),根据对齐方式,读取任何 x[0...15] 将导致仅将那些元素加载到缓存中。

读取元素 x[16] 会将其和后续元素加载到不同的缓存行中。

根据缓存的总大小,读取x[9000] 可能会导致缓存冲突,并且先前填充的行将被清除以为新元素腾出空间。

【讨论】:

    【解决方案2】:

    机器对您的班级布局一无所知,因此班级规模无关紧要。它只知道您实际访问的内存,即您的访问模式。代码编译后,类的布局信息甚至可能不存在在内存中,因此机器无法识别。

    【讨论】:

      【解决方案3】:

      正如其他答案中提到的,内存子系统不知道对象的内存布局。它只看到对相应地址的内存访问。因此,无论您的对象有多大,将始终将相同数量的数据加载到缓存中。

      至于加载多少数据的问题,这取决于架构。在简单系统上,只会加载相应的缓存线。另一方面,现代 x86 cpu 也具有预取机制。这种机制会尝试确定您接下来最可能需要哪些内存地址,并且还会提前获取这些缓存行。这就是为什么顺序访问比随机访问快得多(数量级)的原因,因为在这里预取器总是会选择正确的数据。

      编辑: 但同样:这与您的班级的大小无关,而仅取决于访问模式(这当然可能取决于您班级的内存布局)。

      【讨论】:

        猜你喜欢
        • 2014-05-15
        • 1970-01-01
        • 1970-01-01
        • 2014-02-06
        • 1970-01-01
        • 1970-01-01
        • 2012-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多