缓存性能相当复杂,真正可靠的答案将来自专门负责调度调度的硬件设计人员或操作系统开发人员。我曾经在大型 IBM 系统上使用性能分析工具,所以我可以给出一个部分的、稍微过时的答案:
首先,高速缓存存储器是按地址关联的。如果一块内存被寻址,则该地址的“缓存行”被加载到缓存中。根据处理器设计,这可能是 4、8、16 或 32 个字节的长度。(也许更多。)这很可能基于硬件地址的“对齐”;换句话说,一个 32 字节的行将位于与可被 32 整除的地址对齐的边界上。您的内存引用可能位于该缓存行的开头、中间或结尾。
一旦它在缓存中,该地址就被用作“查找”来查找缓存的数据。
如果缓存行足够大以至于引用了恰好已作为缓存行的一部分缓存的“相邻”项,则引用的局部性将对您有所帮助。跳过你的阵列会打败这个。
缓存设计因供应商、产品线、处理器价格等因素而有很大差异。完美的缓存优化将是非常难以捉摸的,除非(1)您对要运行的机器非常了解,并且(2)您真的对在任何其他机器上运行不感兴趣。
要考虑的另一个因素是 32 位地址的大小是 64 位地址的一半,这对可以缓存的数据量有很大影响。为地址提供更多位意味着或多或少地减少数据位。
预取更多的是巫术而不是科学。从数据中获取内存到缓存是昂贵的,即使它与处理器执行是异步的(尽管它永远不能与执行分离太远)。引用的局部性是一个很好的规则,尽管它将基于硬件架构,其方式不一定与微观尺度上的代码执行相匹配。LRU(最近最少使用)是决定从缓存中引导什么的常用方法,但是从缓存中删除某些内容以便为最终不再使用的内容腾出空间并不是一个很好的优化。因此,至少可以说,预取是明智的。
编辑:虚拟内存问题、任务切换等。
虚拟内存确实让事情变得更加有趣,尤其是在支持多个地址空间的操作系统中。缓存最有可能基于真实地址,而不是虚拟地址,因此页面交换之类的事情可能会对缓存产生有趣的副作用。通常,将要被换出或释放的页面将首先失效,并移动到“刷新列表”(可以将其写入交换文件)或“空闲列表”。根据实现,这些页面仍然可以被应用程序回收,但它们不再是可寻址的——这意味着在回收它们的过程中会发生页面错误。因此,一旦将页面移出应用程序的工作集,与之关联的任何缓存行很可能都会失效。如果页面没有被大量使用,
此外,一些高速缓存设计具有“共享”高速缓存,并且大多数或全部具有特定于处理器和内核的高速缓存。如果缓存被指定给特定的处理器或内核,并且该内核更改了任务,则可能会刷新整个缓存以避免被新进程破坏。这不包括线程切换,因为线程在相同的进程和相同的地址空间中运行。这里真正的问题是系统上其他应用程序的高活动可能会影响您的缓存性能。共享缓存在一定程度上缓解了这个问题,但必须更加小心地管理以避免损坏。