答案 0 :(得分:77)
请参阅我的回答about spatial and temporal locality。
特别是,数组是连续的内存块,因此在第一次访问时,它们的大块将被加载到高速缓存中。这使得访问阵列的未来元素相对较快。另一方面,链接列表不一定在连续的内存块中,并且可能导致更多的高速缓存未命中,这增加了访问它们所花费的时间。
考虑大型结构的数组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
。如您所见,这实际上并不捕获列表中的任何其他元素,这意味着当我们访问l_data->next
时,我们将再次进入内存。
答案 1 :(得分:7)
通常,在使用阵列时,您可以访问彼此靠近的项目。在按顺序访问数组时尤其如此。
当您访问内存时,会在各个级别缓存一大块内存。 缓存局部性是指连续操作在缓存中的可能性,因此速度更快。在数组中,最大化顺序元素访问在缓存中的机会。
对于列表,通过反例,不能保证列表中按顺序出现的项目实际上在内存中彼此靠近排列。这意味着缓存命中次数减少,性能下降。