你真的了解高速缓冲存储器吗?今天这篇文章带你对cache进行一个全面透彻的了解,我们不难知道,由于CPU和主存之间的性能差异越发明显,CPU的计算速度和访存速度差异太大,为了提高CPU的效率,我们引入了高速缓冲存储器,也就是我们上一篇文章所讲的静态RAM(基于双稳态触发器的六晶体管电路(MOS管)),高速度、低容量、高成本的特点。
cache属于存储器的一种,如果有对于存储器不太明白的小伙伴可以先浏览我本专栏的上一篇文章,相信你对存储器一定会有这更深的了解。
提示:以下是本篇文章正文内容,下面案例可供参考
时间局部性原理就是存储器在未来一段时间要访问的信息与现在访问的信息是相同的,也就是说,一个数据在将来的一段时间内会被重复访问,例如循环语句等,这种特征我们管他叫做时间局部性原理。
空间局部性原理指我们所处理的信息的地址空间与未来要使用的信息的地址空间是临近的,因为计算机指令在执行的时候通常是顺序执行的。
请各位老铁仔细观察一下两段代码,他们的局部性原理如何啊
程序一:
include
int func1(int arr[M][N])
{
int i=0;
int j=0;
int sum=0;
for(i=0;i
注释:
首先我们来看第一个程序,论空间局部性原理的话,我们回想一下刚才提到的空间局部性原理的定义是什么?好我们紧接着看这个程序,通过观察我们不难知道,这个函数当中的sum在对数组在进行访问的时候,数组当中的每个元素是完全按照顺序来执行的,对吗?也就是说,程序现在所使用的数据的地址空间和未来要使用的地址空间是临近的,所以这个程序的空间局部性原理是很好的,起码比起第二个程序要好很多。
现在我们来观察他的时间局部性原理,有时间局部性原理可以分析,程序一数组当中的的每一个数据顺序执行,而且每一个数据只执行一次,所以他的时间局部性原理并不好,因为他做不到,程序未来要使用的信息和现在正在使用的信息相同。
程序二:
程序1:
include
int func1(int arr[M][N])
{
int i=0;
int j=0;
int sum=0;
for(i=0;i
注释:
经过程序一的分析相信大家已经能够很好的了解程序访问的局部性原理了,我们来分析程序二,程序二与程序一的最大的不同就是程序对于数组的访问形式,我们通过观察不难得出,如果把数组看作一个矩阵,程序二当中的数组访问顺序是arr[1][0],arr[2][0]....从中可以看出数组每次是跳跃式访问的,没访问一个数据,就要跳过一行,到下一行去访问。所以不难得出他的空间局部性原理是很不好的。
同样的时间局部原理呢?也不会,因为他当中没有循环,数据只使用一次之后再也不使用了,做不到程序未来使用的数据和现在使用的数据是相同的。
cache位于存储器结构的顶层通常由SRAM构成,cache块又称为cache行,每一块都有若噶奴字节组成,块的长度成为块长,由于cache的容量要远远小于主存,所以cache块的数量要远远的小于主存当中的的块数
cache块就是预测未来一段时间内CPU要访存(访存:CPU从内存当中访问数据)的数据,并将其装入cache块。这样子CPU就可以不用每次都到主存(内存)当中去访问了,直接到cache当中寻找想要访问的数据即可。
当CPU在cache当中找到想要访存的数据的时候,这里叫作cache块的命中,如果不命中的话,就必须要去主存当中把欲访问的数据取出来,然后再放入到主存,这样下次在访问这个数据的时候就可以直接到cache当中访问了,这样就大大地提高了CPU的访存效率。(cache块的命中率通常在95%以上)。
原理详解:
温馨提示:
这里涉及到cache和主存之间进行信息交互的原理,是相对重要的一个部分,但很好理解,对于将来打算直接就业不打算考研的小伙伴对其原理了解即可,没有必要对其中的每一个具体运算过程都非常了解,而且面试题当中很少涉及,我们对他有一个初步的了解便于我们日后对于编程的深层次理解即可。
原理:cache行当中的信息其实就是主存当中的一个副本,地址映射就是把主存地址空间映射到cache地址空间,就是把存在于主存当中的某种信息按照一定的规则装入cache当中即可。
主存当中的某一块位置只可以装载到cache块当中的唯一位置,一旦产生冲突,原有的快就会被踢出去
如果大家觉得抽象的话,我举一个例子大家就明白这个变态的映射方式了,为什么说他是变态呢?可以想象一下,你在坐公交车而且车上只有你一个人,你就相当于cache块当中原有的数据,这个时候,车上上来一个大爷,大爷二话不说直接冲到你的身旁让你给他让座,他还振振有词地说年轻人要礼让老年人,这个时候你会很惊讶,车上明明有那么多空位,可这老大爷却只对你的位置情有独钟,你说这是不是很变态呢?
说到这里想必大家就已经明白了,这个老大爷就相当于从主存调来的新的块,即使cache空间有很多空位,但是只要是他选上的块地址,不管有没有空位,原来的块都必须让开,这就容易发生激烈的块冲突,以及块的浪费。
那么全相联映射就很好理解了,主存当中的块可以到cache块当中的任意位置,也就是说老大爷不过会跟你抢座了,起码只要他有位置他就不会让你强行给他让座,这样就不会有太大的块冲突了。
但是还有一个问题,就是寻找的太慢了,就好比说,公交车上有1000个位置,但是做了999个人,“老大爷”会为了这一个座位寻找半天,这样子效率太低,“老大爷”也累得不轻啊。
组相联呢就好很多了,就是把cache块分成好几组,组间直接映射,组内全相联映射,也就是说,把公交车上分成好几个区域,“老大爷”随便找一个固定的区域不再换区,在区内在进行位置的寻找,这其实就是对于以上两种方式的有机结合。
结语:好了说到这里相信小伙伴们已经对于cache——主存的映射方式有了一个全面的了解,虽然举的例子有些生硬,但是可以帮助大家理解。
注释:其实这里就涉及到我们刚才提到的,万一在以上两种方法都试过以后,老大爷还是没有找到座位怎么办,这时候必须有人出来让座。
顾名思义,随机替换呗,“老大爷”随机挑选一位幸(大)运(冤)儿(种)为他让座。
最先上公交车的那个人让座,也就是最先被放到cache块当中的那个数组被踢出去。
cache快当中,哪个数据用的最少,哪个数据用的最少,哪个数据最先被踢出去。
注释:写策略就是当cache当中的内容被更新和修改时,必须保证cahce和主存当中的数据一致,因为CPU总是根据主存当中的数据地址映射到cache查找到相应的数据的,所以必须保证主存当中的数据和cache当中的数据一致。
当CPU对cache写命中时(在原有数据的基础上再写,也就是修改数据的意思),必须把数据同时写入主存和cache,原来的块(修改前)也不必再写入主存,直接由新块(修改后的块)将原来的块覆盖即可。
但是,这个时候遇到了一个问题就是,访存的次数被增加了,要知道CPU直接访问主存的时间损耗是很大的,那么为了减少这个时间损耗,我们就提出在CPU和主存之间的cache一旁设置一个写缓冲区,CPU将对cache修改后的数据写到写缓冲区,再由缓冲区写到主存。
不过这样会再次出现另一个问题,如果写的次数太频繁的话,缓冲区会溢出。
回写法就是等把事情办完以后回过头来再写,也就是当CPU修改cache中的数据时,不着急修改主存当中对应的值,而是等修改完这一块以后,先放着,等需要再次修改的时候,再把旧的值写到主存当中,起到一个转移保存的作用(这个时候已经修改了两次了,但是只进行了一次访存),这就明显地降低了CPU的访存次数
刚才我们提到的时CPU写命中的情况,就是我要修改cache某块中的数据时,找到对应的cache块,但是写未命中就意味着,我要修改的这个数没有在cache块当中找到,那这个时候怎么办呢?这个时候我们提供两种方法。
到此本篇文章的全部内容就讲解完毕了,希望和大家共同进步,也真心希望,各位友友们能够从我的文章当中有所收获,相信大家已经对高速缓冲存储器有所了解了,我的上一篇文章时专门讲述和存储器有关的概念的,如果大家还有不明白的地方,可以订阅的《计算机底层原理》专栏,在这里我将用心的为大家介绍操作系统、计算机网络、计算机组成原理等计算机底层的相关知识,那么下一篇文章将为大家介绍虚拟存储器和指令的相关概念。