取指令——译码——执行——返存
计组课我们学过cpu真正读指令并非是从内存中读入,而是从cache读和存,再由cache进行取指或返存,因为cpu指令周期比内存周期速度快很多,cpu若要取指或返存都需要等待内存完成他的动作才可以进行下一步动作。
我们上一章看过用户进程的地址、虚地址(逻辑地址)和物理地址的地址码
我们回顾一下
用户进程
虚地址
内核模式代码混合使用虚拟,逻辑和物理寻址。每种设备使用多少取决于底层硬件和操作系统。
保护操作系统和用户进程
内存管理的目的
地址转化解决的问题
我们发现虚拟地址可能会是重复的,比如两三个进程的地址都是从0开始,但我们都知道物理地址等于基址加逻辑地址
一个所有进程的逻辑地址集合叫做逻辑地址空间
地址转换的时机
我们分析一下一个程序的的执行周期
源代码编译(汇编)成目标代码
目标代码需要将其他的目标代码等链接起来形成可加载的模块(可执行代码)
加载一些系统库变成二进制文件\镜像
那么逻辑地址是何时转化物理地址呢?
汇编语句中有一条在内存中取指令,那么我们要取址就需要访问地址,操作系统先访问虚拟地址(变址寄存器),加上基址寄存器中的基址得到物理地址,从而取得想要的数据。
但这个前提是加载程序前我们必须要知道基址
缺点:我们的进程空间是无法被移动的(只可以是连续的)
当然只要当我们程序运行时逻辑地址才会被替换成物理地址进行寻址
比如说我们执行call调用的时候
所以当我们运行之前就需要得到进程运行的准确的基址
上面我们提到的换算所需要的单元叫做MMU
曾经的电脑时直接访问物理内存的,现在考虑到安全性和物理内存空间太大才换成这个方式
连续的内存分配机制
这里提到的内存连续性,我们需要关注的是对进程内存的定位、回收、保护。
固定大小分区
内存的分区的大小是固定的,需要系统进行调度
加入我们有一个进程p1占用6k内存大小
此时p2进来占用2k进程,但是我们不能用p1所占剩下的2k空间
所以p1的进程剩下的2k内存空间就被浪费了,浪费的空间叫做内存碎片。
但是当p1执行完毕,被系统释放内存回收之后其他进程依旧可以进入。
实现上面的功能,我们需要记录两个情况,一个是我们有那些区域可用,另一个是那些区域被占用。
这里说了一个问题,最后我们会在内存中看到很多大小不一的“洞”(a hole)
问题演示
假设我们是下面大的进程集需要系统分配空间,那么1、2、3进来之后我们有一个洞,这时候4、5、6可以填补这个洞,那么这时2释放空间之后,我们有第二个洞,那么这个洞只有等7来占用,长此以往下去小的洞会越来越多。
动态存储分配问题
三个算法,分配原理不同,应用场景不同
第二个和第三个都需要便利内存
地址转换与保护
地址越界提示,需要查看变址寄存器
内部碎片
对固定大小内存分区内部产生的空出来的内存空间
外部碎片
可变分区长时间分配之后会产生很多大小不一的洞,这些洞实在太小了无法再被分配,这些洞叫做外部碎片
这里有一个算法,这个算法的原理是将内存一直向上或者向下移动(一个方向),这样就会将碎片覆盖,这个算法叫做compaction
注意:如果这里地址转化是静态的,也就是加载时内存基址被确定,那么这样就无法移动,那么也就无法使用这个算法;还有检测机制是需要有一定开销的,我们考虑是否开销的浪费大于内存碎片的浪费。