存储器的层次结构
先放一张存储结构图。
中心思想是,位于k层得更小更快的存储设备,作为位于k+1层的更大更慢的存储设备的缓存。即层次结构中每一层都缓存来自较低一层的数据对象。
那么存储器采用怎样的机制从k+1层数据中提取一部分放到k层作为缓存呢?
如下图所示,每层都会把所有存储总空间划分为等大小的几个block块(当然,不同层划分的block大小一般不相等,越远离CPU的底层划分的块越大)。那么比如k-1层向 k层拿数据,如果k层没找到(发生了缓存不命中),那么就从k+1层拿取数据块block放到k层,k层原有数据块丢弃。当然,实际上发生缓存不命中时,计算机从k+1层拿取哪些block,又替换k层的哪个或哪几个block是有一些处理机制的,这里就不详述了。(关键词:缓存淘汰算法LRU)
稍微科普一下各级存储器的种类与特性:SRAM 、DRAM 、ROM
寄存器:1个CPU周期即可访问到
ROM:只读存储器,存储在ROM中的程序称为固件。
SRAM:静态随机访问存储器,访问速度最快(几个CPU周期),抗干扰能力强只要有电可以永远保存他的值,常用作高速缓存存储器。
DRAM:动态随机访问存储器,比SRAM慢(几十个CPU周期),抗干扰能力弱需要间隔固定周期重写,常用作主存和图形系统帧缓存。根据读入读出的方式不断改进有SDRAM 、DDR SDRAM等,读写速度在不断改进。
磁盘存储和固态硬盘:读取信息时间为毫秒级,比DRAM慢了10万倍。
磁盘、固态和其他IO设备通过IO总线连接IO桥接器与主存和CPU进行数据流通。
访存的局部性(利用局部性写出缓存友好代码)
- 对局部变量反复引用
一旦从存储器中读入了一个数据对象,就尽可能多的使用他。 - 步长为1的引用模式最好
比如我用一个循环来对vec的每个元素进行操作,那么我逐个访问vec[k]、vec[k+1]、vec[k+2]比跳跃着访问要好。
另外循环体越小(循环体里面的算式少一些),循环的迭代次数越多,局部性就越好。 - 注多维数组操作时的空间局部性
我们很容易知道,数据在存储器中的存储方式是以一维数组或链表存储的,而我们一般遇到的二维乃至多维数据在存储器中的保存方式仍然是一维的。而c语言以行优先存储数组,那么对于数组a[i][j],下面的循环方式中,第一种比第二种好。
for(int i=0;i<n;i++){
for(int j=0; j<n; j++){
a[i][j];
}
}
for(int j=0;j<n;j++){
for(int i=0; i<n; i++){
a[i][j];
}
}