背景
进程执行时需要将程序和数据加载入内存
进程内存空间范围通过基地址寄存器和界限地址寄存器指定
input queue:磁盘上等待调到内存的进程
- 指令和数据绑定到存储器地址的时间:
编译时:1.知道在内存中的地址,生成绝对代码
2.否则生成可重定位代码(如符号)
加载时:将可重定位的地址绑定到绝对地址
执行时:如果程序在执行时可以从一个内存转移到另一个内存,则执行时进行绑定
MMU:(CPU)虚拟地址 -> (内存)物理地址
- 动态加载:
程序以可重定位加载格式保存在磁盘上
当调用某个程序,先检查是否已经加载,否则加载该程序到内存,并更新程序的地址表
- 动态链接库:
可链接到用户程序的系统库
每个库程序的引用都有一个存根(一小段代码):
当程序已经在内存中,进行定位
否则,加载到内存
用程序地址代替自己
交换
- 标准交换(并不使用):
内存与备份存储(快速磁盘)之间
执行进程时,检查是否在内存中,如果不在则需要换入进程
如果没有空闲区域,需要换出内存中的一个进程
如果换出的进程正在等待I/O操作,I/O异步则会将数据存放在进程的buffer上,发生交换时,该内存不属于原来的进程
解决方式:1.不能换出等待I/O操作进程
2.I/O操作的执行只能使用操作系统的缓冲(双缓冲,需要从内核内存再次复制数据到用户内存)
- 现代操作系统交换方式:
1.当空闲内存低于某个阈值时,才允许交换
2.交换进程的部分
移动系统不支持交换,当空间不够时,允许终止进程
连续内存分配
内存容纳操作系统和各种用户进程
操作系统内存分配位于低内存,原因:中断向量位于低内存
每个进程位于一个连续的内存区域
内部碎片:分配的内存比所需的大
外部碎片:当总的可用内存之和可以满足请求但不连续
- 外部碎片解决方式:
紧缩:移动内存内容,合并空闲块
允许逻辑地址空间不连续:分段&分页
- 内存分配方法:
1.分区,每个分区只包含一个进程
2.可变分区,列表记录可用块(first-fit, best-fit, worst-fit)
分段
逻辑地址空间由一组段构成
逻辑地址由<段号,偏移>组成
段表:段基地址+段界限
C编译器创建的段:代码;全局变量;堆;栈;标准C库
分页
物理内存分为固定大小的块:帧/页帧(frame)
逻辑内存分为同样大小的块:页
页表:逻辑地址 -> 物理地址
TLB寄存器:缓存少量页表条目
逻辑地址由<页码,页偏移>组成
页表基地址寄存器:存储页表位置
- 保护:
TLB中包含地址空间标识符ASID:唯一标识每个进程,为进程提供地址空间保护
页表中存放每个帧关联的保护位
页表中的有效-无效位标识相关页是否在进程的逻辑地址空间内
- 共享页:
可重入代码和纯代码可以共享
可重入代码在执行期间不会改变,可以多个进程同时执行
页表结构
- 分层分页
- 哈希页表
哈希表每一个条目包含一个链表(防止碰撞)
链表元素包含虚拟页码,映射的帧码,下一个指针
- 倒置页表
按照物理地址来排序,每个真正的内存页或帧才有一个条目
每个条目包含页的虚拟地址,以及拥有该页的进程信息
整个系统只有一个页表
查询匹配可能需要搜索整个表
共享内存实现困难