一、程序装入内存的三种方式
1. 绝对装入
2. 可重定位装入
3. 动态重定位
从写程序到程序运行的过程
二、程序链接的三种方式
三、覆盖技术
四、交换技术
五、连续分配管理方式
1. 单一连续分配(连续)
2. 固定分区分配(连续)
分区说明表
3. 动态分区分配(连续)
用于存储的数据结构
分区分配算法
- 首次适应算法:空闲分区按照 地址递增次序 链接,每次从 低地址开始查找 ,找到第一个满足大小的空闲分区
- 最佳适应算法:空闲分区按照 容量递增次序 链接,每次分配内存时顺序查找空闲分区链
- 最坏适应算法:空闲分区按照 容量递减次序 链接,每次分配内存时顺序查找空闲分区链
- 邻近适应算法:空闲分区按照 地址递增次序 链接,每次从 上次查找结束的位置开始查找 ,找到第一个满足大小的空闲分区。可以跳过如 首次适应算法中很多低地址部分的小空闲分区。最终剩余的空闲分区比较均匀。
分区的分配与回收: 只要回收的分区与其他空闲分区相邻,则需要合并。
六、基本分页存储管理
页、页面 : 进程被分割后的一个一个部分
页框、页帧: 内存空间被分割后的一个一个部分
页表
地址转换
地址转换例题
注: 如果每个页面大小为 2 k B 2^k B 2kB,用二进制数表示逻辑地址,则末尾 k k k 位就是页内偏移量,其余部分为页号。如果页面大小刚好为 2 2 2的整数幂,则只需要把页表中的记录的 物理块号 与 页内偏移量 拼接就得到 物理地址
地址变换机构
具有快表(TLB)的基本地址变换机构
快表: 是一种访问速度比内存快很多的高速缓存(TLB是cache,不是内存),用来存放最近访问的页表项的副本,可以加快地址变换速度。于此对应,内存中的页表称为慢表。
注: 快表可减少访问内存次数,同时访问快表比访问内存快
引入快表后,地址变换加快
局部性原理
七、两级页表机制
单级页表存在的问题:
- 页表必须连续存放,因此页表很大时,需要占用很多连续的页框
- 没必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面
八、基本分段存储管理
分段存储管理地址变换机构
分页和分段的比较
九、段页式存储管理
段页式地址变换机构
十、虚拟存储技术
传统存储管理方式的特征、缺点
虚拟存储的定义和特征
虚拟存储技术的实现
基本页表和请求页表
缺页中断时的操作
请求分页与基本分页的区别
请求分页需要注意的地方
十一、页面置换算法
1. 最佳置换算法(OPT)
2. 先进先出置换算法
注: 实际上难以实现
3. 最近最久未使用置换算法(Least Recently Used)
4. 时钟置换算法(CLOCK)
5. 改进的时钟置换算法
置换算法的对比
十二、页面分配策略
抖动现象: 刚刚换入内存的页面,马上又要换出。页面频繁的换入换出导致进程无法正常工作。主要原因: 进程频繁访问的页面数目高于可用的物理块数。
十三、堆栈分配
一个由C/C++编译的程序占用的内存分为以下几个部分:
- 栈区(stack) : 由编译器自动分配释放,存放函数的参数值,局部变量的值等。
- 堆区(heap) :由程序员分配和释放,若程序员不释放,程序结束时可能由OS回收。
- 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量、未初始化的静态变量在相邻的另一块区域。
- 文字常量区: 常量字符串就是放在这里的。
- 程序代码区: 存放函数体的二进制代码。
栈 是内存中的一个连续的块。一个叫堆栈指针的寄存器(SP)指向堆栈的栈顶。堆栈的底部是一个固定地址。堆栈有一个特点就是,后进先出。也就是说,后放入的数据第一个取出。
堆 是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。
- 在高级语言中,程序函数调用、函数中定义的变量都用到栈(stack)。
- 用malloc, calloc, realloc等函数分配得到变空间是在堆(heap)上。
- 在所有函数体外定义的是全局量。
- 加了static修饰符后不管放在哪里都属于静态变量,存放在全局区(静态区)
- 在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用。
- 在函数体内定义的static表示只在该函数体内有效。
- 函数中的"armfly"这样的字符串存放在常量区。
int a = 0; //全局初始化区, 可以被其他c文件 extern 引用
static int ss = 0; //静态变量,只允许在本文件使用
char *p1; //全局未初始化区
void main(void){
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区, p3在栈上。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10); //在堆区申请了10个字节空间
p2 = (char *)malloc(20); //在堆区申请了20个字节空间
strcpy(p1, "123456"); /* 123456字符串(结束符号是0,总长度7)放在常量区,编译器可能会
将它与p3所指向的"123456"优化成一个地方 */
}