内存缓存基础概念
本部分主要讨论一些内存缓存上的基础概念,下一章主要讨论一些复杂的内容和结合工业界实际情况(如ARM)的介绍。
内存基础概念
物理地址、虚拟地址
简单但并不完全准确来说,物理地址就是物理内存上可以直接寻址的地址,虚拟地址是操作系统虚拟出来的,一般程序能接触到的地址。物理地址和虚拟地址通过MMU进行映射,对于大部分程序来说是透明的,不需要关心具体的物理地址。
使用虚拟地址主要的好处有:
- 增加可申请内存大小。虚拟地址可以比物理地址有更多位数,比如x64至少可以支持48位。
- 不常用的虚拟内存地址对应的页可以被保存在磁盘上,提高内存利用率和效率。
- 屏蔽了不连续的物理内存地址与内存碎片,暴露给程序的虚拟内存地址一般是连续的。
- 使程序的物理内存地址随机化,增加安全性。
但是对于部分系统,如嵌入式系统,实时系统等,可能有以下缺点:
- 缺页中断时,TLB未命中时,需要从后一级缓存中加载数据,耗时较长且不稳定。
- 少数高性能场合性能优化不可控,见进阶内容中VIPT,VIVT和PIPT的讨论与缓存命中率的讨论。
TLB
TLB主要用于快速的转换虚拟地址和物理地址,可以理解成储存了一部分物理地址和虚拟地址对应关系的字典,一般位于CPU和cache中间。它相当于分页表的缓存,分页表中这保存了虚拟地址对应的物理地址,位于内存中。如果查询的地址不在TLB中,则需要到分页表中拿取对应的地址并将TLB中的一条记录替换,需要耗费较长的时间。
缓存
这里的缓存一般指CPU内部的cache,它减少了延迟并提高了数据带宽。cache遵循了2个局部性原则:被使用的数据在之后也可能被重复使用和被使用的数据周围的数据在之后可能被使用。现代处理器可能有多级缓存,比如L1,L2,L3等。其中部分缓存可能将指令区与数据区分开,如L1d和L1i。最后一级缓存也被称为LLC(Last Level Cache)或者LL,一般这个参数能描述出整体缓存效果,因为在L1-LLC阶段虽然cycle递增,但是整体耗时可接受,而如果数据在内存或者磁盘中,则需要显著更多的cycle去获取数据。
直接映射,全相联和组相联
cache与内存地址的映射关系一般有直接映射,全相联和组相联。
- 直接映射:每个内存地址只能对应一个cache位置
- 全相联:每个内存地址可以对应任意cache位置
- 组相联:cache分为几组,每个内存位置可以对应一组中的任意一个cache位置
注意到,我们在这里没有区分虚拟地址和物理地址,这是因为cache具体结构可能使用物理地址也可能使用虚拟地址,详见进阶内容中的VIVT,VIPT,PIPT的讨论。另外,组相联还有其他变种如skewed associative cache等,详见进阶内容中的讨论。
直接映射电路简单,但是缓存的冲突率高;全相联虽然效果较好,但是电路过于复杂。组相联相对适中,电路不是很复杂,而缓存冲突率和全相联相近。
cache line
缓存的最小单位是cache line,一般是32B,64B或128B。读入或写回内存时,都需要以cache line位单位。
在组相联模式下,内存地址被分为了三个部分与cache line对应:index,tag和offset。index决定了这个内存地址具体放入哪个组,tag用来标记这个cache line,这样在判断一个地址是否已经在缓存中时只需要比较tag是和这个组某个cache line的tag一致即可,offset表示其在cache line中的偏移量。
注意到,我们同样没有指出内存时物理地址还是虚拟地址,详见进阶内容中的VIVT,VIPT,PIPT的讨论。
一般来说,你可以近似认为index,tag和offset是直接由内存地址的某几位决定的。但是注意到在实际上,出于安全和更高缓存利用率等的原因,他们更有可能是内存地址经过某种哈希函数后得到的,例如Intel Skylake的12way组相联和Xeon的20way组相联等。
缓存冲突与miss
注意,此处讨论的不是缓存一致性的冲突问题。
cache miss指的是CPU需要访问某个内存地址时,其数据不在缓存中的情况。此时需要向下一级缓存或内存请求数据。一般每向下一级缓存就需要耗费10倍以上的cycle。
缓存冲突表示在缓存从下一级缓存取回数据时,所有的cache line已满,必须要将某条cache line移出的情况。