最近开始学习操作系统原理这门课程,特将学习笔记整理成技术博客的形式发表,希望能给大家的操作系统学习带来帮助。同时盼望大家能对文章评论,大家一起多多交流,共同进步!
本文主要分以下几个方面:
- 内存的相关概念,将程序放入内存所做的工作
- 逻辑地址与物理地址的概念
- 程序如何进入内存,变成进程
- 内存的管理技术:对实存而言,有交换(Swapping),连续分配(Contiguous Memoty Allocation),分页,分段,段页式(Segementation with Pages)
1. 内存的相关概念
内存:CPU可以直接访问的存储设备(另一设备为寄存器)。区别在于寄存器的访问只需一个时间周期而内存的访问需要多个时间周期;高速缓存(cache)的读取时间在内存与寄存器之间
使用一对寄存器来定义内存的逻辑地址空间,分别为基值寄存器和大小寄存器。
对于单CPU来说只需要两个寄存器来存放当前CPU执行的进程的基值和界限,其他进程的信息则在PCB中。
2. 将指令和数据绑定在内存空间的正确位置上
逻辑地址绑定:
编译时间绑定:absolute code 只允许装载到同一内存单元
装载时间绑定:relocatable code 可重定为代码,进入内存前可允许装载在不同的内存单元,但进入内存后内存单元不可改变
执行时间绑定:可装载在不同的内存单元,且可移动
若进程可移动,则在执行时间时内进行地址绑定,此时需要地址映射的硬件支持。
3. 逻辑地址与物理地址
逻辑地址(Logical Address):程序中所写的地址,用户能看到的地址,相对地址,虚地址
物理地址(Logical Address):内存地址,虚地址,绝对地址
逻辑地址=>物理地址:重定位(relocation)
编译时期/装载时期的地址绑定:逻辑地址与实际地址一致
可执行时期的地址绑定 - 逻辑地址(相对地址)与实际地址不同
内存管理单元(MMU):硬件设备,把逻辑地址变成物理地址,使用寄存器,重定位寄存器存放基值,基值与逻辑地址相加得到物理地址。用户进程只对逻辑地址进行处理,执行时MMU会自动将逻辑地址更换为物理地址。
4. 动态装载(Dynamic Loading)
只在执行时将指令放入内存。优点:不占内存
当程序被调用时,判断该程序指令是否被装载,若未被装载则需要将指令进行装载。该方式下的重定位被称作动态重定位。
而在编译或装载时的重定位被称作静态重定位。
动态链接(Dynamic Linking):将链接推迟到可执行时期。
Load-Time Dynamic Linking 装载时期的动态链接
- 这种方式是指在编译之前并不知道将会调用哪些DLL函数,完全是在运行
- 过程中根据需要决定应调用哪个函数,并用LoadLibrary和GetProcAddress
- 动态获得DLL函数的入口地址。
- 编译的时候不需要头文件,LIB文件
- 运行的时候可有可无动态库文件,如果缺少动态库文件,程序仍然能启动,
- 只是没有动态库里所含的功能而已
存根 stub
对于内存的管理分为分配和回收两步,有以下几种方法:
对换 swapping:另外开辟一块硬盘空间用于进程间交换,类似于动态装载,应用于内存不足的情况
连续分配 Contiguous Allocation:
- 多分区分配法:将内存空间分为n块,每块空间允许进一个程序,分区的大小固定
若分区大小等大:优点:limit寄存器的值不变;缺点:若程序小浪费空间,若程序大不能运行
若分区大小不等大:优点:程序能安全运行;缺点:管理较分区大小等大的情况复杂,需base+limit寄存器,且也可能浪费时间。
hole - 未分配的可用的内存块
input queue输入队列:等待分配内存的进程序列。
OS需包含管理已分配空间和未分配空间的功能: a) allocated partitions; b) free partitions(holes)
管理内存空间的数据结构:起始空间,大小,是否被分配
固定=>空间浪费=>可变分区分配
怎样满足分配一个大小为n的分区的请求:
1. First-fit:从头开始寻找第一个满足要求的hole。优点:快;缺点:浪费存储空间
2. Best-fit:寻找最优匹配的hole,即满足要求的最小空间。优点:不浪费存储空间;缺点:慢
3. Worst-fit:寻找最差匹配的hole,即满足要求的最大空间。优点:剩余的hole有更大的可能被利用;缺点:慢且浪费存储空间
一般来说最优适应和首次适应在时间和空间利用率上要优于最坏适应。
可变分区的回收分为四种:该分区上下均为未利用空间;该空间上方为未利用空间;该空间下方为未利用空间;该空间上下两方均为已利用空间
碎片 Fragmentation 分为外碎片(External Fragmentation)和内碎片(Internal Fragmentation)
外碎片为分区和分区之外不可利用的空间,一般占总空间的50%,出现在可变分区分配
内碎片为分区内的不可利用的空间,出现在不可变分区分配
碎片整理 Compaction(内存紧缩):在程序为动态链接和动态装载时可以使用
compaction时机:所有碎片的空间相加满足进程所需空间
离散分配方式:分页 或 分段
思路:将进程分为几段(若每段大小固定为分页,若每段大小不固定为分段),在分页的情况下将内存也分为大小相同的几段,将进程的各页逐一放入内存中。在分段的情况下则直接将进程的各段放入内存中。
分页时:每个进程最后一页会产生内碎片
分段时:内存的段与段之间会产生外碎片
——————————————————————————————————————————————————————
//2016.4.8 更新
连续分配可分为固定分区分配和可变分区分配,可变分区分配中可使用碎片整理(compaction)
离散分配:分页式(Paging),分段式(Segmentation),段页式(Segmentation with Paging)
离散分配时逻辑地址分配为不连续的。
页框(Frame):固定大小的物理地址块,是2的幂,从512至16MB,由硬件定义(对内存而言)
页(Page):将程序按页框的大小分为固定大小的物理地址块(对程序而言)
将页装入页框即可。
逻辑地址表示:(P,d)-表示在第几页,页面偏移量为多少
需要页表(page table)来找到逻辑地址和物理地址的对应关系。
练习1:某简单分页系统,主存大小64K,页大小为1024B,有四页作业,逻辑地址与物理地址的映射为0,1,2,3=>2,4,6,7,将以下逻辑地址转换为物理地址:
1023 => (0, 1023) => (2, 1023) => 3071
2500 => (2, 452) => (6, 452) => 6596
3500 => (3, 428) => (7, 428) => 7596
4500 => (4, 404) => 越界中断
练习2:简单分页系统,页大小1000B,逻辑地址与物理地址的映射为0,1,2 => 5,2,7
1. 将以下逻辑地址转换为物理地址:
3456 => (3, 456) => 越界中断
256 => (0, 256) => (5, 256) => 5256B
1350 => (1, 350) => (2, 350) => 2350B
2. 将以下物理地址转换为逻辑地址
7568 => (7, 568) => (2, 568) => 2568B
CPU生成的地址可被分为:Page number(P),Page offset(d)
下图为地址转换机构的视线
页表的实现:页表被存放在内存中;页表基值寄存器(PTBR),页表长度寄存器(PTLR)
访问数据或指令需要两次内存访问:一次用于查询页表,一次用于访问数据或指令(有效性:50%)
提高有效性 -> 减小访问内存数量 -> 联想访问缓存(TLBs)
未用TLB -> 访问指令/数据 -> 2*T内存
用TLB :访问到页表 -> TTLB + T内存
未访问到页表 -> TTLB + 2*T内存
内存保护(Memory Protection):
内存区分为页面可读,可写,可执行:Valid-invalid bit 在页表中设置
valid - 页在进程中,是一个合法页
invalid - 该页不在进程的逻辑地址空间内
共享页面(Shared Page)
- 可共享的代码 (pure, reentrant) code 纯代码,可重入代码
- 私有的代码
可重入代码必须出现在所有进程的统一逻辑地址空间
页表长度不能超过一页,因离散分配内存空间。
页表长度过长,需改进页表的数据结构:1. 页表分页(二级页表); 2. 转置页表; 3. 哈希页表
//2016.4.9
页表分页:P1-P2-d
假设每页1K大小,可存页表项500个,则二级页表可以存储500 * 500 * 1K = 250 MB,相比于一级页表500K有巨大的存储提升
对于32位系统,一般页表数据结构分为:P1(12bit)-P2(10bit)(page number) - d(10bit)(page offset)
哈希页表(Hashed Page Tables)
广泛用于地址空间大于32bits的系统中
哈希页表包含一种元素的链表,元素包括:虚拟页编号(The virtual page no.),映射页框号的哈希值(The value of the mapped page frame),指向下一个元素的指针(A pointer to the next element in the linked list)
转置页表(Inverted Page Table):物理地址的每一页对应页表的一项,保存在该物理地址存储的逻辑地址号
优点:1. 降低每一个页表需要的内存空间
2. 只需要一个列表
缺点:1. 查找时间增长 => 可食用哈希表来缩短时间
2. 表占用的内存空间大(虽然只有一个表,尤其是在系统刚启动的时候)
分段式管理(Segmentation):把程序分为段的集合
逻辑地址数据结构:<segment-number, offset> => <段号,段内偏移量>