前言
-
单道程序设计系统中,内存被划分为两部分:
一部分供操作系统使用(驻留监控程序、内核);
一部分供当前正在执行的程序使用。
-
多道程序设计系统中:
在内存中进一步细分出用户部分,以满足多进程要求;
细分的任务由操作系统动态完成 — 内存管理。
一、内存管理需求
重定位
保护
共享
逻辑组织
物理组织
1. 重定位
程序员并不知道进程执行时在内存的位置
-
进程可能被置换到磁盘,再次进入内存时将在不同的位置,需要重定位
必须允许进程通过
swapping
技术在内存移动内存索引(逻辑地址)必须转换成进程的物理内存空间
-
重定位:将逻辑地址转换为物理地址
当进程装入内存时,绝对地址是确定的;
进程在执行期间,可能占据不同的分块(置换);
压缩技术也可能会引起进程占据不同的分块
- 地址类型
-
逻辑地址(相对地址)
- 程序中的访问地址,从 0 开始;
-
物理地址(绝对地址)
- 数据在内存的
-
重定位 — 过程
-
系统采用运行时动态加载的方式把使用相对地址的程序加载到内存。
被加载进程中的所有内存访问都是相对于程序的开始点
-
需要一个硬件机制把相对地址转换成物理地址
基址寄存器 — 载入程序在内存中的起始位置
界限寄存器 — 程序的终止位置
基址寄存器 + 相对地址 < 界限寄存器 — 提供保护
2. 保护
-
内存管理:避免内存中的进程间有意无意的互相干扰,防止地址越界和操作越权;
用户进程不能访问 OS 的任何代码或数据;
进程未经授权不能访问其他进程的内存单元,读或写;
编译时不可能检查绝对地址来确保保护,必须在指令访问内存时判断访问是否违法;
此需求必须由 CPU(硬件)来满足,而不是由 OS(软件)满足。
3. 共享
-
允许多个进程访问内存的同一部分;
多个进程属于同一个程序,每个进程访问程序同一个副本;
合作完成同一个任务的进程可能需要共享访问相同的数据结构;
必须允许共享区域进行受控访问。
4. 逻辑组织
- 程序被组织成模块
某些模块可以独立地编写和编译;
可以给模块不同程度的保护(只读 、 只执行);
模块化易于被多个进程共享。
5.物理组织
-
存储器至少分为两级,如果程序员负责组织信息流
-
供程序和数据使用的内存可能不足
需采用覆盖技术来组织程序和数据,不会被同时调用的共同使用同一内存区
浪费时间
多道程序设计中,程序员并不知道可用空间的大小和位置;
-
内存管理:需要 OS 移动信息完成存储管理功能。
二、内存分区
内存管理技术:固定分区;动态分区;简单分页;简单分段;虚拟内存分页;虚拟内存分段。
分页、分段:离散分配内存空间给进程的页或段
-
分区:连续分配内存空间给一个进程
固定分区
动态分区
1. 固定分区
系统将内存划分成若干边界固定的区域,设定分区说明表;
分区大小相等:小于或等于分区大小的任何进程可以装入可用分区。
分区大小不等:放置算法
把每个进程分配到能够容纳它的最小分区;
使得分区内部碎片最少;
-
调度队列保存换出的进程
-
每个分区一个队列或者只提供一个队列
容纳新进程的最小分区;
考虑优先级;
被阻塞的进程。
-
缺点
分区数目固定,限制了活动进程数目;
分区大小事先设置,小作业不能有效利用分区空间。
2. 动态分区
分区的长度和数目是可变的;
进程被精确分配在相应的内存空间。
缺点:
会产生很多空洞 — 外部碎片;
-
克服空洞,引入压缩技术
OS 不停移动内存中的进程,使碎片连成一片;
费时,并要求动态重定位。
动态分配 — 放置算法
-
最佳适配(Best Fit)
空闲区按大小递增顺序排列,选择与要求的大小最接近的块;
性能最差,更经常地压缩。
-
首次适配(First Fit)
从开始扫描内存,选择大小足够的第一个可用块;
低地址有许多碎片,高地址端有大空间可用;
最简单的,最好的,最快的。
-
下次适配(Next Fit)
从上一次放置位置开始扫描内存,选择下一个大小足够的可用块;
末尾最大的存储块很快分成小碎片,需要多次压缩。
3. 伙伴系统
折中方案
伙伴:两个大小相等的相邻分区;
2^U 表示可用的整个内存的大小;
-
算法:如果请求的大小 s 满足 2^(U-1) < s ≤ 2^U ,则分配整个空间;
否则,分成两个大小相等的伙伴,均为 2^(U-1),如果有 2^(U-2) < s ≤ 2^(U-1),则分配其中任何一个;
直到产生大于或等于 s 的最小块。
4. 分页
内存被划分为固定大小的块 — 页框 frame;
进程也划分成同样大小的块 — 页 page;
-
此技术为每个进程浪费的空间仅仅是 一 小部分内部碎片
最后一页产生内部碎片;
无外部碎片。
-
OS 需要为每个地址维护一个页表
页表项包含内存中的用于保存相应页的页框号;
进程进入内存分配页框,并创建页表;
CPU 必须知道如何访问当前进程的页表
逻辑地址包括一个页号和在该页中的偏移量
分页 — 地址装换
- 地址转换步骤:
提取页号;
对应页号,找到页表中的页框号 k;
物理地址:k * 2^m + 偏移量(m 是偏移量的位数)。
练习题:页式存储管理系统中,某进程页表如下。已知页面大小为 1024 字节,问逻辑地址 600,2700,4000 所对应的物理地址各是多少?
答:
逻辑地址 600 在 0# 页,放在 7# 页框。页内偏移地址为 600。
对应的物理地址为:600:7×1024+600=7768
2700 在 2# 页,放在 5# 页框,页内偏移地址为:2700 mod 1024=652
对应的物理地址为:2700:5×1024+652=5772
逻辑地址 4000 在 3# 页,越界
5. 分段
分段技术:把程序和其相关的数据划分到几个段中,有长度限制,但不一定相等;
逻辑地址 = 段号 + 偏移量;
段大小不等,类似于动态分区;
段表给出相应的段在内存中的起始地址和段的长度;
段表的地址装入寄存器,供内存管理硬件使用。
分段 — 地址转换
分段 — 转换机制
练习题:在一个简单分段系统中,包含如下段表:
对如下的每一个逻辑地址,确定其对应的物理地址或者说明段错误是否会发生:
答:
a. 段 0 定位在 660,所以我们有物理地址 660 + 198 = 858。
b. 段 2 的起始地址是 222,222 + 156 = 378。
c. 段 1 长度为 422,所以会发生错误。
d. 996 + 444 = 1440。
e. 660 + 222 = 882。
三、安全问题
1. 缓冲区溢出(内存越界)
-
输入到一个缓冲区或者数据保存区的数据量超过了其容量,从而导致覆盖了其他信息。
可能由编程错误造成;
会被攻击者利用,攻击系统
-
错误后果:
程序使用数据损坏;
程序中控制流发生意外改变;
违法的内存访问;
程序终止。
-
为了利用各种缓冲区溢出类型,攻击者需要
找出程序中的外源数据触发的缓冲区溢出漏洞;
了解缓冲区将如何在进程内存中存储,从而发现损坏相邻内存单元及改变程序执行流的可能性
通过追踪程序可以发现易受攻击的程序;
通过特定工具,可以自动发现潜在地易受攻击的程序。
预防缓冲区溢出
编译时防御系统,强化系统以抵制潜伏于新程序中的恶意攻击 — 止执行缓冲中的代码;
运行时防御系统,检测并中止现有程序中的恶意攻击 — 检测到异常及时中止。
四、补充内容
覆盖技术:把一个程序分为一系列功能相对独立的程序单元,让执行时并不要求同时装入内存的单元成一组,共享同一个存储区域。
覆盖技术要求程序员必须把一个程序划分成不同的程序段,并规定好它们的执行和覆盖顺序,操作系统根据程序员提供的覆盖结构来完成程序段之间的覆盖。
交换技术(swapping):把暂时不用的某个程序及数据部分或全部从内存移到外存中去,以便腾出必要的内存空间,或把制定的程序或数据从外存读到相应的内存中,并将控制权转给它。
覆盖主要在同一个作业或同一个进程内进行,并且只能覆盖那些与覆盖程序段无关的程序段;而交换主要是在进程或作业之间进行。