我正在审核一个面试问题并与朋友比较笔记,我们对CPU缓存有不同的想法。
考虑一大组数据,例如大量double
,即:
double data[1024];
考虑使用动态分配的动态链表来存储相同数量的元素。这个问题要求描述一些权衡因素:
O(n)
),只需提供一个索引({{1 }})。O(1)
,而链表需要逐元素比较加解除引用开销。在memcmp()
点,这是我们的意见不同的地方。我认为CPU将尝试缓存整个阵列,如果阵列非常大,它就不能存储在缓存中,因此没有缓存优势。使用链接列表,可以缓存单个元素。因此,链接列表适合缓存"点击"在处理大量元素时,不仅仅是静态数组。
问题:两者中哪一个更适合缓存"命中",现代系统可以缓存阵列的一部分,还是他们需要整个阵列,或者它不会尝试?任何对技术文档或标准的引用,我也可以用来提供明确的答案,这将有很大的帮助。
谢谢!
答案 0 :(得分:4)
CPU不了解您的数据结构。它缓存或多或少的原始内存块。因此,如果您认为每次都可以多次访问同一个元素而不遍历列表,那么链表和数组都没有缓存优势。
但是,与动态分配的链表相比,数组具有很大的优势,可以按顺序访问多个元素。因为CPU缓存在大于一double
的内存块上运行,所以当一个数组元素在缓存中时,驻留在相邻地址的其他几个也可能在缓存中。因此,从主存储器读取一个(慢速)可以访问对多个相邻阵列元素的(快速)高速缓存访问。链接列表也不是这样,因为节点可以分配在内存中的任何位置,甚至单个节点至少具有next
指针的开销,以稀释可以缓存的数据元素的数量。时间。
答案 1 :(得分:2)
缓存不了解数组,他们只看到内存访问并在该地址附近存储一点内存。一旦你在一个地址访问了某些东西,它应该在缓存中停留一段时间,无论该地址是属于数组还是链表。但是缓存控制器并不真正知道正在访问的内容。
当您遍历数组时,缓存系统可能会预取数组的下一位。这通常是启发式驱动的(可能带有一些编译器提示)。
某些硬件和工具链提供内在函数,可让您控制缓存驻留(通过预取,显式刷新等)。通常你不需要这种控制,但是对于像DSP代码,资源受限的游戏控制台和需要担心缓存一致性的操作系统级别的东西,看到人们使用这个功能是很常见的。