第二节:内存层次结构
当有人们提到“内存”这个词的时候,往往都与主板上的专门提供数据存储能力的芯片联系起来。通常将这类提供存储能力的芯片称之为随机存储器(RAM),主内存(main memory),和主存储器(primary storage).回首计算机的铁器时代,大型机大行其道的时候,称之为核心部件(core)。这些芯片提供的存储只是临时的,也就是说,存储在这些芯片里的数据只要当电源被关闭以后也随之消失。
有这么几类RAM
动态 RAM(DRAM)一秒钟内会进行数千次的充电动作。同步 DRAM (SDRAM) 随着处理器高速的时钟运行速度下保持同步刷新。静态 RAM(SRAM)不需要像DRAM那样频繁的刷新,这使得它的速度大大加快。不幸地是,SRAM的价格也比DRAM昂贵得多,只得以被少量的使用。 SRAM适合用于处理器的高速缓存,DRAM则适用于大规模的主存储器。最后还有一种视频RAM(VRAM),它是一种有视频硬件使用的一类内存。在下一章中,会有一个例子用语演示如何通过控制VRAM来向屏幕输出信息。
最近随着某些硬件厂商对技术的不断进步和特别的性能优化实现又衍生出很多新的缩写出来,下面有几个:
DDR SDRAM是双倍数据传输速率的同步随机存储器。使用DDR SDRAM 数据可以在一个系统时间周期的上升沿和下降沿同时读取数据,基本上两倍于常规的可用带宽。RDRAM是Rambus DRAM的简称,由Rambus公司出售的高性能版本的DRAM,它可以达到800MHz的传输速率。增强型的同步DRAM(ESDRAM),由 Enhanced Memory Systems,Inc 公司生产,作为取代SRAM的一种更廉价的SDRAM。
1(bit)比特是一个二进制数,(例如一个1或者一个0)。RAM中由比特这样的基本单元结构构成,依据RAM的类型,以某种晶体管和电容器的布局方式组成。每一个单元是一个可以设置为‘开’ 和‘关’的数字开关(例如:1或者0)。这些单元每八个分为一组成为字节(bytes)。字节是用来计量存储器所提供的内存总量的的基本单位。在过去,硬件厂商曾经使用不同大小的byte单位。有些使用6比特作为一个字节,还有使用16字节作为一个字节。而现在所有人都遵守了相同的8比特一为个字节的标准。
以下是以byte为单位的内存单位容量说明。
1 byte = 8bits
1 word = 2bytes
1 double word = 4bytes
1 quad word = 8bytes
1 octal word = 8bytes
1 paragraph = 16bytes
1 kilobyte(KB) = 1,024bytes
1 megabyte(MB) = 1,024KB = 1,048,576bytes
1 gigabyte(GB) = 1,024MB = 1,073,741,824bytes
1 terabyte(TB) = 1,024GB = 1,099,511,627,776bytes
1 petabyte(PB) = 1,024TB = 1,125,899,906,842,624bytes
注解:在80年代,拥有一个上M的DRAM内存已经很了不起了。孩子们不断的游说父母再升级16KB的内存,让他们在Atari400可以玩上更复杂一些的游戏。在那个时候只有1M内存并不是什么大问题,因为软件工程师们都倾向使用汇编代码构建更加精巧的程序。实际上,经常有人引用比尔盖茨于1981年的一句话:"640K的内存对于每个人都绰绰有余了"
而今,大多数用于开发的计算机至少拥有128M的DRAM,在2002年拥有256M被视为是标准配置。此后的十年内。上G的内存将作为标准配置出现。(如果我们仍使用DRAM)。希望以后不要有人引用我的这段话。
RAM并不是唯一存储数据的地方,这里引出了我们内存层次结构的议题。不同的数据存储位置,根据与处理器的远近关系排列。排列后产生了如下层次结构:
1.Registers 寄存器
2.Cache 高速缓存区
3.RAM 主内存
4.Disk storage 硬盘
这些存储器之间最大的区别在于存储时滞或者说延迟。访问靠近处理器的存储设备所用的时间比相对稍远处理器的存储器少。处理器访问硬盘上数据的时间远远的大于处理器访问它内部的高速缓冲区数据的响应速度。比如,DRAM往往使用纳秒来衡量时滞,而硬盘的时滞,却是用毫秒来衡量!(如下表1.1)
图 1-1
寄存器是位于处理器内部的小型存储器。寄存器是处理器钟爱的工作区。处理器的大部分日常工作是对寄存器中的数据进行处理。将数据在寄存器之间移动,是最为实用的数据移动方式。工程师们在设计的编译器时跨越种种难题,力求将所有变量和常量都保存在寄存器中。应用程序状态保存在处理器内部所拥有的大量寄存器中从而降低了存储时滞。因此MIPS64处理器设计了32个64位的通用寄存器。安腾——INtel的下一代64位处理器,更加不可匹敌,它有用竟然数百个寄存器。
Intel Pentium处理器拥有多种寄存器(如图 1-2)其中:6中16位的段寄存器(CS,DS,ES,FS,GS,SS)。8位,32位通用寄存器(EAX,EBX,ECX,EDX,ESI,EDI,EBP,ESP )还有一个32位的错误标志寄存器(EFLAGS)用以标识错误状态,以及一个32位的指令指针寄存器(EIP)。
图 1-2
高级内存管理的功能得到由四种系统寄存器(GDTR,LDTR,IDTR,TR)和五种模式控制寄存器(CR0,CR1,CR2,CR3,CR4)协助。这些寄存器的使用方法会在后面介绍。
注释: 注意很有意思的是由于历史的原因Pentium处理器的寄存器数量受到了限制。由于向后的兼容性的设计需求,使得Pentium处理器所拥有的寄存器数量比当年的8086没有太多增加。
高速缓冲区提供访问速度大于DRAM的临时存储器。通过将程序部分集中放置在高速缓冲区中的进行运算的方式,处理器可以避免重复访问DRAM所带来的性能开销,这个效果十分显著。有不同类型的高速缓冲区。L1缓冲区是位于存储器内部的存储器。L2是典型的SRAM类型存储器,于处理器外部。(例如,Intel Pentium4搭载了这样256或者512KB的高速缓存器)
注释: 如果你正在尝试针对高速缓冲区优化程序代码,你应该避免不必要的函数调用。调用一个远程函数需要处理器执行高速缓冲区以外的代码。这将会导致重新装载高速缓冲区里的内容。这也便是为什么某些C编译器提供内联函数功能选项的原因。从另一个方面来说,使用内联函数比不使用内联函数的程序体积更大(占用更多的存储器空间)时间和空间的互换的取舍平衡的问题一直贯穿整个计算科学领域。
硬盘是数据存储的最后一个位置。通常,硬盘常常用于创建虚拟内存。虚拟内存使用硬盘空间来模拟主内存。换言之,将一部分存储在DRAM上的数据写入硬盘,处理器便可以访问的内存总量大于实际物理内存。例如,如果你有10MB的DRAM内存并且使用了2MB的硬盘空间作为虚拟内存,处理器便可以访问12MB的虚拟内存。
注释:我将在本书中反复重申的一点是硬盘I/O的严重性能损耗。正如我之前所提到的,硬盘是使用毫秒为单位来横定响应能力的。处于处理器来说这个时间太过漫长。这个情形就类似远在北达科他州做pizza的小店,如果运气好的话,你冰箱里有一个冷冻pizza,加热只需要30分钟。否则你不得不给那个pizza小店叫份pizza外卖(就好象访问硬盘上的数据)然后花上几个小时等待外卖小子跨越150英里的距离送到你的房间。
使用虚拟内存就好象跟魔鬼打交道,当然你会获得很多扩展内存,但是你会在性能上付出昂贵的代价。硬盘I/O涉另一整套的操作行为,其中还有一些物理机械性的。Windows系统的内存分页,粗略的估计会因此占用10%的执行时间。管理虚拟内存还需要生成大量的内存信息记录。我会在后面详细的谈论有关虚拟内存信息记录的内容。
题外话
我曾经在一家ERP的公司工作过,其中一位副主管常常对过度滥用硬盘I/O的工程师处以罚金。在代码复审时候,他会用grep命令搜索源代码里面的所有 fopen()和fread()标准库函数。我们接受了这样基本课程:你应该尽可能的将一切缓存到内存中只有在别无选择的情况下才将数据保存到硬盘中(这个操作甚至需要得到他的许可)。归功于该副主管,公司的三层中间件产品成为产业中性能最高的。
硬盘总是比RAM便宜,在60年代买一块8KB的RAM花费不菲,用硬盘虚拟内存或许很有意义。今天,硬盘和DRAM的价格差距并不是像以前那样那么明显了。买一台512MB内存的计算机并不是大不了的事情。虚拟内存可能会完全成为历史或者成为某些紧急情况下的数据安全方案。