文章目录
之前在介绍linux——文件的时候讲了一下磁盘及其工作原理。然后又在程序员自我修养专栏讲了一下程序在内存中的布局。但是我们还是没有打通CPU和内存是怎么进行交互这一件事。这也是本文的一个目的。
内存呢,是存在于CPU和硬盘之间的一个桥梁。硬盘负责存储数据,CPU负责对数据进行操作。而内存呢,则是他们两个的缓冲区。要明白内存是如何和CPU甚至和磁盘交互的,就不得不先看一下内存的储存器。
内存的存储
内存的存储器叫做随机访问存储器,一般分为两类:
- 静态SRAM
- 动态DRAM
SRAM 比 DRAM更快,但是也贵的多。SRAM用来作为高速缓冲存储器,一般用在CPU上。对!告诉缓存Cache就是SRAM。而DRAM 则用来作为主存以及图形系统的帧缓冲区。
SRAM
SRAM 将每个位存储在一个双稳态的存储单元里。什么叫双稳态呢?看下面这幅钟摆图:
每个单元都是用六个晶体管电路来实现的。这个电路有这样一个特性:可以无限期保持在两个不同的电压状态,也就是在上图左(右)稳态。其他任何状态都是不稳定的——从不稳定状态开始,电路会迅速的转移到两个稳定状态中的一个。
上图其实有个地方应该是有偏差的,也就是中间那个状态。原则上来说,当左右两边的作用力相同时,钟摆在垂直的时候也能无限期地保持平衡,但是当左右两边稍微发生一点扰动,这个状态就会变成左稳态或右稳态之一。而且一旦倒下,便不会有机会再站起来。我们称这个状态为亚稳态。
因为SRAM有双稳态的特性,只要有电,它就会永远的保持它的值。即使有干扰来扰乱电压,当干扰时,电路就会恢复到稳定值。但是没有电的话,双稳态的状态就不能保持了,意味着数据也就丢失了。这就是我们常说,电脑断电后内存数据就会丢失的原因。
DRAM
DRAM将每个位存储为对一个电容的充电。DRAM可以制造得非常密集——每个单元由一个电容和一个访问晶体管组成。但是与SRAM不同的是,DRAM存储器的单元对干扰非常敏感。当电容的电压被扰乱之后,它就永远不会恢复了。
下图总结了SRAM和DRAM的区别。
- SRAM的存取比DRAM快
- SRAM对干扰不敏感
- SRAM每单元使用更多晶体管,密集度低,比DRAM更贵,功耗更大
DRAM内部以及与内存控制模块的交互(重点)
再DRAM芯片中,每个大单元内部又有d个超单元,每个超单元都由w个DRAM单元组成(每个单元其实就是一个位)。所以说,一个d*w的DRAM总共村拿出了dw位信息。超单元被组织成一个r行c列的长方形阵列,其中r*c = d
,每个单元有形如(i,j)的地址(i表示行,j表示列)。
博主说:
还是有点抽象,这么说吧。假如说w = 8,也就是一个超单元存储一个字节,那么d个超单元就存储d个字节。
信息通过称为引脚(pin)的外部连接器流入和流出芯片。每个引脚携带一个1位的信号。上图中给出了两组引脚:
- 8个data引脚,他们能传送一个字节到芯片或从芯片传出一个字节
- 2个addr引脚,它们能携带2位的行和列超单元地址
每个DRAM芯片被连接到某个称为内存控制器的电路。这个电路可一次传送(读出)w位到每个DRAM芯片。为了读出超单元(i,j)的内容,内存控制器会将行地址 i 发送到DRAM,这个时候就会在超单元矩阵中选出 i 那一行,复制到内部行缓冲区。
然后地址引脚addr会把列地址 j 传入,这个时候会在刚刚选出的哪一行中再选出第 j 个元素返回给内存控制器以相应。
设计者把DRAM组织成二维阵列而不是我们平常抽象出的一维数组的原因是降低芯片上地址引脚的数量。例如,图中的那个128位的DRAM被组织成一个16个超单元的线性数组(16*8 = 128),这个时候对引脚进行编号,那就是0~15,正好是2^4,需要四个addr引脚而不是两个addr引脚。但是,二维阵列会进行两步操作,所以它会比线性组织耗费更多的时间。
DRAM与内存存储
DRAM 芯片被封装在内存模块(一个内存模块会有多个DRAM),以64位为块传送数据到内存控制器。
下图展示了内存模块的基本思想,用8个64Mbits的8M*8的DRAM芯片,总共存储64MB,这8个芯片编号0~7。每个超单元存储主存的一个字节,而用相应超单元地址(i,j)的8个超单元来表示主存中字节地址A处的64位字。
博主说:
其实也就是A的第一个字节存储在DRAM 0的(i,j)位置,第二个字节存储在DRAM 1的(i,j)位置…
要取出内存地址A处,那么就去每个DRAM的(i,j)处去取这个相应的字节再拼装起来。
CPU和内存的交互(重点)
CPU和内存交互,内存在内部其实就反应在内存控制模块和DRAM的交互。
数据流通过总线的电子电路在处理器和DRAM主存之间来来回回。 每次CPU和主存之间的数据传送都是通过一系列步骤来完成,这些步骤称为总线事务。 其中读事务从主存传送数据到CPU,写事务从CPU传送数据到主存。
下图中就是一个他们之间交互的一个图:
我们现在再从一个汇编指令来看看到底怎么回事:movq A,%rax
(地址A的内容被加载到寄存器%rax中)
上图中的总线接口发起读事务,有三个步骤:
- CPU将地址A放到系统总线上
- IO桥将信号传递到内存总线
- 主存感觉到内存总线上的地址信息,从内存总线读地址,从DRAM取出数据放到内存总线
写事件呢,就相反。
磁盘
磁盘的存储基本知识再linux——文件中都讲过了,这里也不赘述了。直接来讲一讲CPU如何去访问磁盘的。
磁盘和CPU、内存的交互
CPU使用一种称为内存映射I/O的技术来向I/O设备发送命令。在使用内存映射I/O的系统中,地址空间中有一块地址是为与I/O设备通信保留的。每个这样的地址称为I/O端口。
来看一个简单的例子:
假设磁盘控制器映射到端口0xa0。随后,CPU通过执行三个对地址0xa0的存储指令发起磁盘读:
- 发送一个命令字,告诉磁盘发起一个读,其中还发送了其他参数
- 指明应该读的逻辑块号
- 指明应该存储磁盘扇区内容的主存地址
当CPU发出请求之后,它可不会采用同步的方式,这是对CPU性能的极大浪费。它会先处理其他的事情。
而磁盘收到这么一个读命令,它将逻辑块号翻译成一个扇区地址,读该扇区的内容,然后将这些内容传送到主存,这期间不需要CPU的干涉。这个过程就叫直接内存访问。当数据到主存之后,CPU就会发送一个中断信号来通知CPU。
博主说:
还不知道中断是什么的,可以参考博客:系统调用过程
这里面讲了软中断,但实际上磁盘应该属于硬中断,差不太多,理解就可。
参考文献
[1] 深入理解计算机系统 第六章 存储器层次结构