首页 > 代码库 > 存储模型(上)
存储模型(上)
进程地址空间:
可以看到进程分成内核地址空间和用户地址空间(可能这就为什么trap要涉及到内核栈与用户栈的切换)
地址重定位:
原因:在进程运行之前因为不知道进程地址空间到底放到什么地方,所以无法计算出物理地址,所以需要地址重定位
逻辑地址(相对地址):
用户程序经过编译,汇编后形成的目标代码,目标代码主要采用相对地址,即首地址为0,其他地址是相对于基地址而编址
不能用逻辑地址在内存中读取信息
物理地址(绝对地址):
内存中存储单元地址
可以直接寻址
地址重定位:为了让CPU能正确访问内存单元,将逻辑地址转换成物理地址的过程叫地址重定位
静态重定位(一般由软件完成):
一次性将逻辑地址转化成物理地址
缺点:一旦进程在内存中位置改变,又要重定位
动态重定位(一般由硬件完成):
在程序加载进内存中不重定位,在进程执行过程中进行地址变换(每条指令执行时完成地址转换)
CPU得到指令的逻辑地址,加上重定位寄存器内容(存放进程加载进内存的起始地址)得到物理地址
物理内存管理:
内存可以被两种方式划分:等长划分和非等长划分
位图(适用于等长):每个分配单元对应于位图中的一位,0表示空闲,1表示占用(或者相反)
空闲区表(分配区表,可以等长或不等长):
表中每一项记录了空闲区(或已分配区)的起始地址、长度、标志
空闲区链表:
将空闲区表项加个指针,然后通过链链接起来
内存分配算法(都会产生外碎片):
1.首次适配
在空闲区表中找到第一个满足进程要求的空闲区
2.下次适配
对首次适配的改进,在上次找到的空闲处接着往下寻找
3.最佳适配
在满足进程地址空间大小的一些空闲区中,找出最小的空闲区
4.最差适配
在满足进程地址空间大小的一些空闲区中,找出最大的空闲区
内存回收情况:
当某块空闲区归还后,前后空闲空间合并,修改内存空闲区表
a左右都不相邻
b右相邻
c左相邻
d左右都相邻
伙伴系统buddy system
主要思想:
把内存按2的幂进行划分,组成若干空闲块链,查找该链表找到能满足进程要求的最佳匹配块
算法:
ps.直接看例子,概念很恶心
例子:
第2步:进程需要100K,100K<1M故将1M对半分,100K < 512K,将512K对半分,100K < 256K,将256K对半分,此时128K/2 < 100K < 128K,所以将128K那区域(注意是整块)分配给进程A(这样就产生了内碎片),其他分配同理
第9步:将C释放后,左右64K位伙伴关系且都为空闲,故可以将两者合并成128K(合成的要求是两者空闲且为伙伴关系)
思路:将比较合适的进行对半分,将大的空闲块保留(就像第三步为什么不把512K那块拿出来对半分成256K给进程B)
内存管理方案:
单一连续内存:
特点:一段时间内只有一个进程在内存简单,内存利用率低
固定分区:
思想:
1.把内存分成若干区域称为分区
2.每个分区大小可以相同也可以不同
3.分区大小固定不变(确定后大小不能改变)
4.每个分区只能装一个进程
示意:
a图中内存分成几个分区,然后如果该分区大小满足某个进程大小就把该进程挂到该分区队列中,分区空闲了,该进程就进入执行了
b图是对a的改进,a图缺点很明显,分区4大小满足该进程,分区2也能满足,但是该进程还是会等在分区4队列中,所以把所有进程拍成队列,让OS去分配那个分区给其使用
可变分区:
思想:根据进程的需要,把内存空闲空间分割出一个分区,分配给该进程
缺点:出现外部碎片,导致内存利用率下降
对于碎片的解决方案:
紧缩技术(memory compaction)
在内存移动程序,将所有小的空闲区合并为较大的空闲区
但是对于移动程序会出现:系统开销 ? 移动时机? (例如某个进程正在进行I/O调用,可能会出现影响,打印出来的结果不正确)
-----------------------------------------------------------------------到此的方案是进程进入内存中连续区域,以下是进入内存中不连续区域---------------------------------------------------
页式存储方案:
思想:
1.用户进程地址空间被划分为大小相等的部分,称为页(page)或页面,从0开始编号
2.内存空间按同样大小划分为大小相等的区域,称为页框(page frame),从0开始编号;也称为物理页面,页帧,内存块
内存分配规则:
以页为单位进行分配,并按进程需要的页数来分配;逻辑上相邻的页,物理上不一定相邻
典型页尺寸:4K或4M
页式存储中
逻辑地址划分成:
在32位系统中:
PS.2^12 = 4K, 划分是由系统自动完成的,对用户是透明的
例子:
进程中某页映射到物理内存中某页框,但是出现了一个问题,一页中指令执行完后想要执行下一页指令怎么办,因为逻辑上相邻物理上不相邻?
出现了页表:
页表就相当于一个大数组:下标为逻辑页号,页表项中存着物理内存上的页框号
页表性质:
页表项:记录了逻辑页号与页框号的对应关系
每个进程一个页表,存放在内存中
页表起始地址保存在PCB中,当该进程指令时,CPU通过PCB中的页表起始地址找到页表完成映射
使用空闲内存管理
地址转换(硬件支持)
CPU取到逻辑地址,自动划分(硬件完成)为页号和页内地址;用页号查页表,得到页框号,再与页内偏移量拼接成为物理地址
缺点:
假设某进程为5页加1条指令,那么这个一条指令也会占去1页,并且该页不能再存其他东西,这就造成了页内的碎片(内碎片)
段式存储管理方案
设计思想:用户进程地址空间按程序自身的逻辑关系划分为若干个程序段,每个程序段都有一个段名(代码段,程序段等等),内存空间被动态划分为若干长度不相同的区域,称为物理段,每个物理段由起始地址和长度确定
内存分配(规则):以段为单位进行分配,每段在内存中占据连续空间,但各段之间可以不相邻
逻辑地址分成
(页式中由于知道页面大小所以可以自动划分,但是段式由于逻辑关系所以无法自动划分)
段表性质:
1.段表项记录了物理段的起始地址和长度
2.每个进程有一段表,存放在进程中
3.段表起始地址也存在PCB中
缺点:
同样在段间留下外碎片问题,造成存储空间利用率降低。
地址转换:
CPU取到逻辑地址,用逻辑段号查段表得到该段在内存的起始地址,与段内偏移计算物理地址
段页式管理方案
设计思想:
综合页式、段式方案的优点,克服二者的缺点
用户进程划分:先按段划分,每一段再按页面划分
内存划分:以用户进程页面划分大小划分成大小相等的页框
内存分配:以页为单位进行分配
逻辑地址:
性质:
段表记录每一段的页表起始地址和页表长度
页表记录了页号与页框号的对应关系
每段有一张页表,一个进程有多个页表
地址转换:
先用段号去查段表得到这一段的页表,然后用逻辑页号去查找对应的页框号,加上页内地址偏移就得到物理地址
空闲区管理与内存管理与页式相同
内存不足时,如何解决在较小内存空间运行较大进程?
覆盖技术:
当程序大小超过物理内存总和,程序执行过程中,程序的不同部分在内存中相互替代,按照其自身的逻辑结构,将那些不会同时执行的程序段共享同一块内存区域,这就要求程序各模块之间有明确的调用结构
程序员声明覆盖结构,操作系统完成自动覆盖
例子:
B,C两个程序段不会同时进行,所以将两者运行放到同一个覆盖区0,覆盖区大小由两者中最大空间为准,若B执行将B加载到覆盖区0,C执行将C加载到覆盖区0,下面同理
缺点:
增加用户负担,因为程序员声明覆盖结构,操作系统完成自动覆盖,
交换技术:
设计思想:
内存空间紧张时,系统将内存中某些进程暂时移到外存,把外存中某些进程换进内存,占据前者所占用的区域(进程在内存与磁盘之间的动态调度)
待解决的问题:
进程的哪些内容要交换到磁盘?会遇到什么困难?
在磁盘的什么位置保存被换出的进程?
交换时机?
如何选择被换出的进程?
如何处理进程空间增长?
解答:
1.主要是运行时创建或者修改的内容:堆栈,代码段主要执行代码基本不变无需交换出去
2.交换区:一般系统会指定一块特殊的磁盘区域作为交换空间(swap space),包含连续的磁道,操作系统可以使用底层的磁盘读写操作对其高效访问
3.只要不用就换出(很少再用);内存空间不够或有不够的危险时换出
4.考虑进程的各种属性;不应换出处于等待I/O状态的进程
5.
对于进程空间增长我们从进程外部和内部入手,(a)在进程外部预留一些空间来给进程增长,(b)图进程执行中增长的部分主要是数据段和栈所以在数据段和栈之间预留一些空间,栈让其往下增长,数据段让其向上增长
作者水平有限,文章肯定有错还请各位指点!!!感谢!!!
存储模型(上)