在没有专门研究存储器系统之前,我们依赖的存储器模型是一个很简单的概念,也就是把它看成一个线性数组,CPU 能在一个常数时间内访问任何一个存储器位置。虽然在研究别的问题时,这是一个有效的模型,但是它不能反映存储器系统的实际工作方式。

存储器系统(memory system)是一个具有不同容量、成本、访问时间的存储器层次结构。CPU 寄存器保存着最常用的数据;靠近 CPU 的小的、快速的高速缓存存储器(cache)作为一部分存储在相对慢速的主存储器(简称主存)中的数据;主存用来暂时存放存储在容量大、慢速磁盘上的数据;磁盘又作为通过网络连接的其他机器的磁盘上的数据的缓冲区域。

存储器层次结构是可行的,因为一个编写良好的程序总是倾向于更频繁访问某一层次上的存储设备。所以,下层的存储设备可以更慢速一点,也因此可以更大、更便宜。

计算机程序有一个重要的基本属性,叫做局部性原理(locality)。具有良好局部性原理的程序比局部性差的程序更多地倾向于在存储器层次结构中的较高层次处访问数据,因此运行的更快。

作为一个程序员,你应该理解存储器系统,因为它对应用程序的性能有着巨大的影响。如果了解系统是如何将数据在存储器层次中上上下下移动的,那么你就可以编写你的应用程序,使数据尽量存储在层次较高的地方,CPU 能更快得访问到它们。

计算机技术的成功很大程度上源于存储技术的巨大进步。

随机访问存储器

随机存取存储器(RAM, Random-Access Memory),有两种类型,第一种叫做静态 RAM(static RAM)。SRAM 将每个位存储为一个双稳态(bistable)的存储器单元里,每个单元用一个六晶体管电路来实现。这种电路有一种限制,就是可以无限期保持两种不同的电压状态之一。由于其双稳态特性,只要有电,它就会永远保持它的值。

动态 RAM(Dynamic RAM),将每个位存储为对一个电容的充电。DRAM 存储器可以制造得非常密集,每个单元由一个电容和访问晶体管组成。与 SRAM 不同,DRAM 对干扰非常敏感,且被干扰后永远无法恢复。存储器系统必须周期性地通过读出,重写来刷新存储器的每一位。

SRAM 是只要有供电,那它就会保持不变,不需要刷新。SRAM 速度比 DRAM 快,对干扰不敏感,但也贵得多。SRAM 用来作为高速缓存存储器,DRAM 用来作为主存以及图形系统的帧缓冲区。

非易失性存储器

如果断点,那么 DRAM 和 SRAM 会丢失信息,所以他们是易失(volatile——的。非易失性存储器(nonvolatile memory)即使是在关电后,依然保持它们的信息。如果想让数据持续保持,要考虑使用非易失性存储器。PROM(Progrommable ROM)可编程只读存储器,只能被编程一次。可擦写可编程 ROM(Rrasable Progrommable ROM,ERPOM)有一个透明的石英窗口,允许光透过,照射存储单元。紫外线照射,这个单元就被清除。对 ERPOM 的编程是通过一种特殊设备完成。ERPOM 的擦写和重编程的次数可以达到1000次。电子可擦除 ROM(Electrically Erasable ROM,EEPROM)可以在印制电路卡上编程。闪存(flash memory)是一种基于 EERPOM 的非易失性存储器。它是一种重要的存储技术,为大量电子设备提供快速、持久的非易失性存储,例如数码相机、手机、笔记本、台式机、音乐播放器等。

访问主存——总线

数据流通过称为总线(bus)的共享电子电路在处理器和 DRAM 主存中来来回回。每次 CPU 和主存之间的数据传送都是通过一系列步骤来完成的,这些步骤称为“总线事务”(bus transaction)。读事务从主存传送数据到 CPU,写事务从 CPU传送数据到主存。

总线是一组并行的导线,能携带信号、数据、地址。多个设备可以共享同一根总线。数据和地址信号可以共享一组线,也可以用不同的,取决于总线的设计。信号的作用是同步事务,标识当前正在被执行事务的类型。

总线配置:主要部件是 CPU 芯片、I/O 桥芯片组(包括存储控制器),DRAM 存储器模块。这些部件由总线连接起来。系统总线连接 CPU 和 I/O 桥。存储器总线连接 I/O 桥和主存。I/O 桥的作用是将系统总线的电子信号翻译成存储器总线的电子信号。总线设计是计算机系统中复杂而又变化迅速的方面。使用简单而抽象的模型是很有用的,可以掌握主题思想而不必与私有的设计细节绑得太紧。

假设 CPU 需要从硬盘中读取一些数据,就发起读事务,会给定指令,逻辑块编号和目标地址,并发送给存储器总线。主存感受到信号,就读地址,从 DRAM 中取出数据,写到存储器总线,然后信号沿着总线返回 CPU。假设 CPU 需要把寄存器的内容写到主存上,就发起写事务,CPU 还是先将地址放到系统总线上,存储器从存储器总线读出地址,然后等待数据到达。 CPU 将寄存器内容拷贝到系统总线上,最后主存从存储器总线读取这些数据,然后存储到 DRAM 中。

磁盘

磁盘(disk)是由盘片(platter)构成的,每个盘片有两个面,或者成为表面(surface),表面覆盖着磁性记录材料。盘片中央有一个可以旋转的主轴(spindle),它是的盘片以固定速度旋转,速度通常在5000 ~ 15000 转每分钟。磁盘通常包含一个或多个盘片,封装在一个密封的容器内,整个装置被称为磁盘驱动器(disk drive),简称为磁盘。

每个表面是由一组成为磁道(track)的同心圆组成的。每个磁道划分成一组扇区(sector)。每个扇区包含相等数量的数据位(比如 512 字节),数据就编码在扇区上的磁性材料中。扇区之间有一些间隙(gap)。术语柱面(cylinder)来描述多个盘片的驱动器,柱面是所有盘片表面上到主轴中心的距离相等的磁道的集合。

磁盘容量

容量是指磁盘可以记录的最大位数,由下面几个因素决定:

  • 记录密度(recording density,位/英寸):track 中 1 英寸能保存的字节数
  • 磁道密度(track density,道/英寸):1 英寸直径能保存多少条 track
  • 面密度(areal density,位/平方英寸):上面两个数值的乘积

$ 磁盘容量 = \frac{字节数}{扇区} × \frac{平均扇区数}{磁道} × \frac{磁道数}{表面} × \frac{表面数}{盘片} × \frac{盘片数}{磁盘} $

假设一个磁盘有 5 个盘片,每个扇区 512 个字节,每个面 20000 个磁道,每条磁道平均 300 个扇区。则磁盘容量是:

$ 磁盘容量 = \frac{512 字节}{扇区} × \frac{300 个扇区}{磁道} × \frac{20000 个磁道}{表面} × \frac{2 个表面}{盘片} × \frac{5 个盘片}{磁盘} = 30 720 000 000 字节 = 30.72 GB $

读写操作

磁盘用读/写头来读写存储在磁性表面的位,当磁道上的每个位通过它的下面时,读写头能够感知到这个位的值,也能修改这个位的值。读写头连接在一个传送臂(actuator arm)的一端。通过旋转,传动臂可以将读写头定位在磁盘上的任何磁道上,这个行为叫做寻道(seek)。在任何时刻,所有读写头位于同一柱面。

寻道时间:

$ T_{avgseek} $ 通常在 3 ~ 9 ms,一次最大的寻道时间 $ T_{maxseek} $ 可以达到 20 ms。

一旦读写头定位到了期望的磁道,下一个行动就是等待目标扇区的第一个位旋转到读写头下。最好情况下就是要读取的位刚好在读写头下,最差的情况就是需要旋转一整圈。

旋转时间:

\[T_{avg rotation} = \frac{1}{2} × \frac{1}{RPM} × \frac{60 secs}{1 min}
\]

RPM 是指:rotation per minute 每分钟旋转次数,RPM 的倒数就是 MPR ,即每转一圈需要的分钟数。乘以二分之一后转换单位即可。

当寻道和旋转都完成了之后,驱动器就可以开始读或写内容了。读写传送时间依赖于旋转速度和每条磁道的扇区数目。粗略估计一个扇区以秒为单位的平均传送时间如下:

\[T_{avgtransfer} = \frac{1}{RPM} × \frac{1}{平均扇区数 / 磁道} × \frac{60 secs}{1 min}
\]

传送时间 = 转一圈所需分钟数 × 一个扇区占一个磁道的占比

  • 访问磁盘扇区的主要时间是寻道时间和旋转时间。开始访问第一个字节要耗时很久,但访问剩下的字节几乎不需要时间。
  • 寻道时间和旋转延迟差不多。

例如有一个如下参数的磁盘

参数
旋转速率 7200 RPM
平均寻道时间 9ms
每条磁道的平均扇区数 400

平均旋转时间:

\[T_{avgrotation} = \frac{1}{2} × \frac{1}{7200} = 4 ms
\]

传送时间:

\[T_{avg transfer} = \frac{1}{7200} × \frac{1}{400} = 0.02 ms
\]

总时间为:

\[T_{access} = T_{avgseek} + T_{avgrotation} + T_{avgtransfer} = 13.02 ms
\]

固态硬盘

基于闪存的磁盘驱动器,称为固态硬盘(Solid State Disk,SSD),是替代传统磁盘的极有吸引力的替代产品。闪存翻译层(flash translation layer)是一个硬件设备,扮演与磁盘控制器相同的角色。闪存芯片替代传统磁盘中的机械驱动器。固态硬盘中分成很多的块(Block),每个块又有很多页(Page),大约 32-128 个,每个页可以存放一定数据(大概 4-512KB),页是进行数据读写的最小单位。对一个页进行写入操作的时候,需要先把整个块清空后才能写这一页,而一个块大概在 100,000 次写入之后就会报废。

与传统的机械硬盘相比,固态硬盘由半导体存储器构成,没有移动的部件,因此在在读写速度上有很大的优势,能耗低,更结实。SSD 也容易磨损。

程序的局部性原理

一个编写良好的计算机程序常常具有比较好的局部性(locality)

  • 时间局部性(Temporal Locality): 如果一个信息项正在被访问,那么在近期它很可能还会被再次访问。程序循环、堆栈等是产生时间局部性的原因。
  • 空间局部性(Spatial Locality): 在最近的将来将用到的信息很可能与现在正在使用的信息在空间地址上是临近的。
  • 顺序局部性(Order Locality): 在典型程序中,除转移类指令外,大部分指令是顺序进行的。顺序执行和非顺序执行的比例大致是5:1。此外,对大型数组访问也是顺序的。指令的顺序执行、数组的连续存放等是产生顺序局部性的原因。

一般而言,具有良好的局部性的程序比局部性差的程序运行得更快。计算机系统的各个层次,硬件、操作系统、应用程序,都利用了局部性。

下面来看局部性原理在程序设计时的体现。我们来看看一个利用循环对数组求和的函数对于每个数据引用的模式

int sumv(int *v, int N)
{
int i, sum = 0;
for(i = 0; i < N; i++)
{
sum += v[i];
}
return sum;
}

因为数组中的元素是一个接一个访问的,因此有很好的空间局部性。由于每个元素只访问一次,因此时间局部性很差。对于循环体中的每个变量,函数要么有很好的空间局部性,要么有很好的时间局部性。因此这个函数有良好的局部性。

我们说像 sumv 函数这样访问数组的函数,具有 步长为 1的引用模式(stride-1 reference pattern)每隔 k 个元素进行访问,就叫 步长为 k 的引用模式。一般来说,随着步长的增加,空间局部性下降。对于多维数组来说,步长就是一个很重要的问题。

一些看上去很小的改动对程序的性能会有很大的影响。步长越小,空间局部性越好。如果在存储器中以大步长跳来跳去,空间局部性很差。了解了高速缓存的工作原理后,就能明白为什么具有良好局部性的程序通常比局部性差的程序运行得更快。

存储体系

存储技术和计算机软件的一些基本属性:

  1. 硬件存储技术:不同的存储技术的访问时间差异很大,速度快的技术成本较高,速度慢的技术容量较大。不同的存储技术有不同的价格和性能折中,也以不同的速度在变化。
  2. 软件:一个编写的好的计算机程序倾向于展现出良好的局部性。
  3. 硬件和软件的这些基本属性互相补充得很完美。它们这种补充性质让人们想到一种组织存储器系统的方法,就是存储器层次结构(memory hierarchy)。从高层往底层走,存储设备变得更慢,但也变得更便宜,容量更大。


参考链接

【CSAPP笔记】11. 存储器层次结构的更多相关文章

  1. [CSAPP笔记][第六章存储器层次结构]

    第六章 存储器层次结构 在简单模型中,存储器系统是一个线性的字节数组,CPU能够在一个常数访问每个存储器位置. 虽然是一个行之有效的模型,但没有反应现代系统实际工作方式. 实际上,存储器系统(memo ...

  2. CSAPP阅读笔记-存储器层次结构-第六章-P400-P462

    6.1 存储技术 1.随机访问存储器(RAM),是易失性存储器,掉电存储信息会丢失,与之相对的是非易失性存储器(ROM),它掉电后存储信息不丢失,但前者访问速度较快,但容量有限,通常只有几百或几千兆字 ...

  3. 【深入理解计算机系统CSAPP】第六章 存储器层次结构

    6 存储器层次结构 存储器系统(memory system)是一个具有不同容量.成本和访问时间的存储设备的层次结构.CPU 寄存器保存着最常用的数据.靠近 CPU 的小的.快速的高速缓存存储器(cac ...

  4. CSAPP:第六章 存储器层次结构

    存储器层次结构 关键点:内存 6.1 随机访问存储器6.2 局部性6.3 存储器层次结构 6.1 随机访问存储器   随机访问存储器(Random-Access Memory,RAM)分为两类:静态的 ...

  5. 【CSAPP笔记】12. 高速缓存存储器

    高速缓存存储器 在存储层次结构中,高速缓存存储器,也叫 cache 是最接近 CPU 寄存器的那一块. 更一般而言,缓存(caching)是一个无所不在的技术.缓存的意思是:对于每层的存储设备,位于 ...

  6. [CSAPP笔记][第九章虚拟存储器][吐血1500行]

    9.虚拟存储器 为了更加有效地管理存储器且少出错,现代系统提供了对主存的抽象概念,叫做虚拟存储器(VM). 虚拟存储器是硬件异常,硬件地址翻译,主存,磁盘文件和内核软件的完美交互. 为每个进程提供一个 ...

  7. [CSAPP笔记][第一章计算机系统漫游]

    计算机系统漫游 我们通过追踪hello程序的生命周期来开始对系统的学习—–从它被程序员创建,到系统上运行,输出简单的消息,然后终止.我们沿着这个程序的生命周期,简要介绍一些逐步出现的概念,专业术语和组 ...

  8. JAVA自学笔记11

    JAVA自学笔记11 1:Eclipse的安装 2:用Eclipse写一个HelloWorld案例,最终在控制台输出你的名字 A:创建项目 B:在src目录下创建包.cn.itcast C:在cn.i ...

  9. 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...

随机推荐

  1. JavaWeb基础—MySQL入门小结

    一.数据库概述 RDBMS:关系型数据库管理系统 == 管理员(manager)+仓库(database) 常见数据库:  Oracle(神喻):甲骨文 MySQL: 归于甲骨文旗下(高版本系统已经开 ...

  2. IntelliJ IDEA教程之如何clean或者install Maven项目

    一.前言 Eclipse中如果我们想clean或者install工程,我们只需要右键工程,然后找到run->Maven install 或者run->Maven clean就可以了,但是I ...

  3. WPF 学习笔记-在WPF下创建托盘图标

    原文:WPF 学习笔记-在WPF下创建托盘图标 首先需要在项目中引用System.Windows.Forms,System.Drawing; using System; using System.Co ...

  4. 2 python介绍

    1.Python介绍:龟叔 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,Guido开始写Python语言的编译器.Python这个名字,来自Gui ...

  5. 05-session-会话跟踪技术

    1.session简介 Django中默认支持Session,其内部提供了5种类型的Session供开发者使用: 数据库(默认) 缓存 文件 缓存+数据库 加密cookie Session是服务器端技 ...

  6. HDU - 5289 Assignment (RMQ+二分)(单调队列)

    题目链接: Assignment  题意: 给出一个数列,问其中存在多少连续子序列,使得子序列的最大值-最小值<k. 题解: RMQ先处理出每个区间的最大值和最小值(复杂度为:n×logn),相 ...

  7. 用Angule Cli创建Angular项目

    Angular4.0来了,更小,更快,改动少 接下来为Angular4.0准备环境和学会使用Angular cli项目 1.环境准备: 1)在开始工作之前我们必须设置好开发环境 如果你的机器上还没有安 ...

  8. 斐讯K2 PSG1218 刷机教程 基于Breed互刷 清除配置

    Padavan官方论坛http://www.right.com.cn/forum/thread-161324-1-1.html Breed官方文档http://www.right.com.cn/for ...

  9. Unity特殊文件夹详解

    ##1.Editor Editor文件夹可以在根目录下,也可以在子目录里,只要名子叫Editor就可以.比如目录:/xxx/xxx/Editor 和 /Editor 是一样的,无论多少个叫Editor ...

  10. Unity3D画面渲染官方教程(一)对光照和渲染的介绍

    本系列是对官方教程的翻译加上自己的一些理解译著的,官方网址:https://unity3d.com/cn/learn/tutorials/s/graphics 翻译上尽量保证准确性,但不排除省略或者添 ...