目录
二.内存
现代计算机的运行中心
由字或字节组成
每个字或字节都有自己的地址
程序(进程)必须装入内存才能被执行
基本硬件
程序必须装入内存才能被执行
CPU可以直接访问的存储器只有主存和寄存器
寄存器通常可以在一个或者少于一个CPU时钟周期内完成访问
完成主存访问可能需要多个CPU时钟周期
-
CPU暂停(Stall)
-
在读取内存数据时,CPU空闲
-
-
两种寄存器
-
基址寄存器(Base)
-
进程最小的合法物理内存地址
-
-
界限寄存器(Limit)
-
进程地址的长度
-
-
-
CPU在执行指令时,需要进行地址合法性的验证
-
逻辑地址和物理地址
-
逻辑地址(Logical address)
-
由CPU产生
-
在进程内的相对地址
-
也称:虚拟地址,相对地址,程序地址
-
-
物理地址(Physical address)
-
内存地址
-
所有内存同意编址
-
也称:绝对地址,实地址
-
-
-
动态加载和动态链接
内存管理
连续内存分配
-
分类
-
单一连续分配
-
固定分区分配
-
可变分区分配
-
-
内存组成
-
分为两部分
一部分:驻留操作系统
一部分:保存用户进程
-
-
单一连续分配
-
特点
-
固定分区分配
-
可变分区分配
-
管理
-
分配算法
分页内存管理
-
基本方法
虚拟内存
进程必须放入内存才能运行
但并不是所有代码都需要装入,可能只需要一部分便可运行
动态的装入进程
例如:装入A可以运行,此时用到了B才去将B装入
-
部分装入的优点
-
进程大小不受物理内存的限制
-
每个进程所需要的内存更小
-
更多进程可以并发运行
-
I/O更少
-
虚拟存储技术
进程运行时,将一部分装入内存,另一部分暂留在磁盘(外存)
执行或者访问的数据不在内存时,在装入内存
-
虚拟内存
-
内存和磁盘结合使用,得到一个很大的“内存”,即虚存
-
-
虚拟地址空间
-
分配给进程的虚拟内存
-
-
虚拟地址
-
在虚拟内存中指令或者数据的位置
-
虚拟页式存储管理
将内存分为很多 帧
进程分为很多 页
当需要执行时,将页放入帧
-
优点
-
I/O少
-
不需要的不用I/O
-
-
内存占用空间小
-
可以容纳的用户更多
-
缺页中断
当访问一个内存帧中不存在的进程页时
会触发缺页中断
访问会停止
-
缺页中断步骤
-
访问指令或者数据
-
查看另一个表来决定:
-
无效引用->终止
-
仅仅不在内存
-
-
找到页在后备存储上的位置
-
得到空的页框,把页换入页框
-
重新设置页表,把有效位设为v
-
重启指令
-
内核内存分配
内核需要为不同大小的数据结构分配内存
同事一些内核内存需要连续的物理页
所以通常从空闲的内存池中获取内存块
-
内核使用内存块的特点
-
内存块的尺寸比较小
-
占用内存块时间短
-
要求快速完成分配和回收
-
不参与交换
-
频繁使用尺寸相同的内存块,存放同一结构的数据
-
要求动态分配和回收
-
伙伴(Buddy)系统
内存按照2的次幂进行划分(4kb,8kb等)
组成若干空闲块的链表
查找链表找到最满足进程需求的最佳匹配快
-
前提条件
-
满足要求是2的幂单位
-
请求不为2的幂,则需要调整到下一个更大的2的幂
-
分配需求小于现在可用内存时
-
当前段分为两个更小的2的次幂
-
继续上述操作直到段的大小合适
-
-
-
整体步骤
-
整个可用空间看成 :2的n次幂
-
申请空间大小为s
-
如果满足 2的n-1次幂<s<2的n次幂,则分配整块
-
否则切分空间为2个 2的n-1次幂
-
-
重复上述操作(此时可用空间 看成2的n-1次幂)
-
-
优点
-
可用通过合并而快速的形成更大的段
-
-
缺点
-
调整到下一个二的次幂容易产生碎片
-
例如 s为17k,那么分配必须为32kb 那么碎片则为32-17=15k
-
极限情况,可能有近50%的内存会浪费掉
-
Slab分配
由一个或者多个物理上连续的页组成
一个Cache(高速缓存)含有一个或者多个slab
每个内核数据结构都有一个Cache,包含了他们的对象(信号量对象等)
进程描述符、文件对象、信号量等
-
slab的三种状态
-
满的:slab中所有对象标记使用
-
空的:slab中所有对象标记空闲
-
部分:slab中部分对象使用,部分对象空闲
-
-
整体步骤
-
创建cache,包含若干个为空闲的对象(数量和slab的大小有关)
-
需要内核对象时,直接从cache获取,标记对象为使用
-
一个slab状态为满的时,下一个对象的分配从另一个空slab中开始
-
如果没有slab则从物理连续页上,分配新的slab
-
-
-
优点
-
没有因碎片而引起内存浪费
-
每个内核数据结构有对应的cache
-
cache由若干个slab组成
-
slab分若干个与对象大小相同的部分
-
-
内存请求可以快速满足
-
对象是预先创建,只需要修改状态(空闲,使用)
-
-
虚拟内存存在的其他问题
预调页
页大小
TLB范围
反向页表
I/O互锁
程序结构
-
预调页
-
进程启动初期,缺少大量的页
-
这个时候在引用前,调用进程的所有或者部分需要的页
-
注意(预调页的成本是否小于处理缺页中断的成本)
-
预调页的页面没使用,可能内存浪费
-
-
页大小
-
页大小总是2的次幂,一般4kb-4mb
-
降低页大小,就增加了页的数量,因此页增加了页表的大小
-
4mb虚拟内存
-
1kb->4096页
-
8kb->512页
-
每个进程有自己的页表,较大的页比较理想
-
-
较小的页,内存碎片更小
-
极端情况下,进程的最后的一页可能会浪费一半
-
如果是8kb则是4kb
-
1kb则是512b
-
-
I/O开销需要大的页
-
I/O包括了 寻道、延迟、传输时间
-
虽然传输时间与传输量(页大小)正比
-
但是寻道时间和延迟时间远比传输时间大
-
读入1kb 28ms
-
读入2个512字节反而 56ms
-
最小化I/O时间需要大的页
-
-
-
程序局部需要小的页
-
小的页---可以精确的匹配程序局部
-
较大的页---可能传输不必要的数据
-
更小的页导致了更少的I/O操作,和更少的总的内存分配
-
-
缺页次数--大的页
-
每个缺页产生大量开销,为了降低缺页操作次数,需要更大的页
-
-
-
TLB的命中率
-
TLB范围=(TLB大小)*(页大小)
-
理想情况下,一个进程工作集应该放在TLB中,否则有大量的缺页中断
-
增加页大小或者提供多种页大小
-
对于不需要大页的程序,导致了碎片增加
-
-
对于大部分程序8kb大小的页足够,对于需要大页的程序,比如数据库。有机会使用大页,也不会增加碎片大小
-