DRAM基本知识及操作系统内存管理策略

DRAM 入门时的一些笔记,虽然比较白痴但还是扔到博客上吧。

一、DRAM工作原理概述

DRAM(Dynamic Random Access Memory)即动态随机存储器,由许多重复的“单元”——cell组成,每一个cell由一个电容和一个晶体管(一般是N沟道MOSFET)构成,电容可储存1bit数据量,充放电后电荷的多少(电势高低)分别对应二进制数据0和1。由于电容会有漏电现象,因此过一段时间之后电荷会丢失,导致电势不足而丢失数据,因此必须经常进行充电保持电势,这个充电的动作叫做刷新(self-refresh),这个刷新的操作一直要持续到数据改变或者断电。因此,DRAM具有掉电易失性。

在内存中,cell按矩阵形排列,每一行(row)和每一列(column)都会有一个对应的行地址线路(word line)和列地址线路(bit line),每个cell对应一个唯一的行号和列号,即内存的地址。Bank是指内存中的一串独立的数组,每个bank可以独立控制,是一个相对独立的存储体,有自己的地址译码单元和刷新再生放大器,彼此之间互不影响,各个bank靠存储芯片上的bank地址(BA)选择。

一些术语:

  • RAS: row address strobe
  • CAS: column address strobe
  • WE: write enable
  • Address: code to select memory cell location
  • DQ(I/O): bidirectional channel to transfer and receive data
  • DRAM cell: storage element to store binary data bit
  • Refresh: the action to keep data from leakage
  • Active: sense data from DRAM cell
  • Pre charge: standby state

DRAM读取过程:
1) 通过地址总线将行地址传输到地址引脚;
2) /RAS引脚被激活,行地址被传送到行地址门闩线路中;
3) 行地址解码器根据接收到的地址数据选择相应的行;
4) /WE引脚被确定不被激活,所以DRAM知道它不会进行写入操作;
5) 通过地址总线将列地址传输到地址引脚;
6) /CAS引脚被激活,列地址被传送到列地址门闩线路中;
7) /CAS引脚还同样具有/OE引脚功能,所以Dout引脚向外传输数据;
8) /RAS与/CAS都不被激活,那么进入下一周期的数据操作。

读取过程中的访问时序如下图所示:

先执行预充电(PRECHARGE)操作,对将要访问的bank预充电,使得其刷新再生放大器处于不稳定的中间状态,随时准备锁存数据;再执行激活(ACTIVE)操作,使得该bank中选定的行 (也称为页,以下同)在bank内部读出,并暂存在刷新再生放大器中,可随时输出到数据总线上;然后执行读(READ)操作,由列地址选定的数据从刷新再生放大器中输出到芯片外部的数据线上,访问过程结束。

DRAM数据写入过程与读取过程类似。

二、内存分区

1.固定分区(Equal-size partitions)

固定分区将内存分为同样大小的区块,小于或等于分区大小的任何进程可以装入到任何可用区块中;若所有分区都满了,操作系统可以换出一个进程的分区。
缺点:程序可能太大而不能放入到一个分区中(需使用overlay技术);内存利用率低,容易产生内部碎片(internal fragmentation)。
解决方法:大小不等的分区。

2.动态分区

分区可变长度可变数量,但容易产生外部碎片(external fragmentation),即所有进程占用分区外的存储空间变成碎片。
解决方法:压缩。

操作系统如何决定将哪个空闲块分配给进程?

  • Best-fit algorithm,总体性能较差,需要经常做内存压缩。
  • First-fit algorithm,容易使内存前端出现很多小的空闲分区,且每次进行首次适配算法查找时都要经过这些分区。
  • Next-fit algorithm,容易导致空间末尾的最大空闲块很快分裂成小碎片,需要经常做压缩。
  • Buddy system,整个空间被看作是一个大小为 $$2^U$$ 的块,如果请求的大小s满足 $$2^U-1 < s <= 2^U$$ 分配整个块;否则该块被分成两个大小相等的块,这个过程一直继续直到产生大于或等于s的最小块。

三、虚拟内存

一些术语:

  • 常驻集(Resident Set):进程执行中总是在内存中的部分。
  • 系统抖动问题(thrashing):系统耗费大量时间在作内存块的交换,而不是在执行指令。
  • 局部性原理:一个进程中程序和数据的引用具有集簇倾向。

分页:每个进程有一个页表;每个页表项(PTE, page table entry)包含有与内存中的页相对应的帧号;两个必须的指示位: 页是否在内存中(Present)和页在上次读入后有没有被修改(Modified)。


另:倒排页表(Inverted Page Table)。倒排页表用于 PowerPC, UltraSPARC, IA-64 体系结构中,虚拟地址的页号部分使用一个简单的散列函数映射到散列表中,散列值指向倒排表中的一个页表项,散列表和倒排表都需要实存的一个固定部分。

转换检测缓冲区Translation Lookaside Buffer (TLB) :给定一个虚拟内存,处理器首先检查TLB,如果页表项在其中 (TLB hit),取出帧号,并形成实地址;如果页表项在TLB中没有 (TLB miss), 则处理器用页号检索进程页表。在进程页表中,首先检查该页是否在内存中,如果不在,则产生一个page fault(缺页中断),当操作系统装入所缺的页后,TLB被更新。


分段:每个段表项包含相应段在内存中的起始地址和段的长义;每个段表项中需要一个表明相应段是否在内存中的位,还需要一个修改位,表明相应的段从上一次装入内存到目前为止内容是否被修改。


段页结合:用户地址空间被程序员划分成许多段,每个段依次划分成许多固定大小的页。


置换策略

当内存中所有帧都被占用时,需要读入一个新页,应当置换内存中的哪一页。

  • Optimal:最佳策略选择置换下次访问距当前时间最长的那些页,这要求操作系统必须知道将来的事情,这不可能。
  • Least recentlu used(LRU):置换内存中上次使用距当前最远的页,根据局部性原理,这也是最近最不可能访问到的页。难于实现——一种方法是给每一页添加一个最后一次访问的时间标签,这开销非常大。
  • FIFO:可能会出现更多的page faults。
  • Clock:给每个页面帧关联一个附加位,叫使用位。当页面第一次读入内存中,该内存帧的使用位设为1,当该页随后被访问到时,它使用位也被置为1;用于置换的候选页帧集合被看作是一个循环缓冲区。当需要置换一页时,操作系统扫描缓冲区查找使用位为0的页帧,查找过程将遇到的使用位为1页帧置为0。

下面将各种置换策略进行对比: