在以下博客中,有一个关于数组相对于链表的优势的声明:
阵列具有更好的缓存局部性,可以在性能上产生很大的不同。
这意味着什么?我不了解缓存局部性如何提供巨大的性能优势。
Answers:
请参阅我有关时空局部性的答案。
特别是,数组是连续的内存块,因此它们的大块将在首次访问时加载到高速缓存中。这使得访问数组的未来元素相对较快。另一方面,链接列表不一定位于连续的内存块中,并且可能导致更多的高速缓存未命中,从而增加了访问它们的时间。
考虑数组data
和l_data
大型结构的链表的以下可能的内存布局
Address Contents | Address Contents
ffff 0000 data[0] | ffff 1000 l_data
ffff 0040 data[1] | ....
ffff 0080 data[2] | ffff 3460 l_data->next
ffff 00c0 data[3] | ....
ffff 0100 data[4] | ffff 8dc0 l_data->next->next
| ffff 8e00 l_data->next->next->next
| ....
| ffff 8f00 l_data->next->next->next->next
如果我们要遍历该数组,则第一次访问ffff 0000
将需要我们进入内存以进行检索(CPU周期中非常慢的操作)。但是,在第一次访问之后,阵列的其余部分将位于缓存中,随后的访问将更快。有了链表,第一次访问也ffff 1000
将需要我们去记忆。不幸的是,处理器将直接缓存该位置周围的内存,一直到为止ffff 2000
。如您所见,这实际上并没有捕获列表中的任何其他元素,这意味着当我们访问access时l_data->next
,我们将再次不得不进入内存。
通常,使用数组时,您访问彼此靠近的项目。当顺序访问数组时尤其如此。
当您访问内存时,会在不同级别上缓存其中的一部分。 缓存局部性是指连续操作在缓存中并因此更快的可能性。在阵列中,您可以最大化在缓存中进行顺序元素访问的机会。
对于列表,作为反例,不能保证列表中顺序出现的项实际上在内存中彼此排列在一起。这意味着更少的缓存命中次数,并且降低了性能。