一、概要
基本概念: 操作系统对内存的划分和动态管理。
带来的好处: 方便用户实用存储器、提高内存利用率、通过虚拟技术从逻辑上扩充内存。
OS提供的功能: ①内存空间的分配和回收 ②地址转化 ③内存扩充 ④存储保护
二、知识扩充
在进行具体的内存管理之前,我们先了解有关背景知识。
(1)内存、外存、主存、辅存?
参考雨临Will_Wong的博客
①顾名思义: 正所谓:“ 晴对雨,地对天,天地对山川。山川对草木,赤壁对青田。内存对外存,主存对辅存。”
②内存和外存: 计算机内部的存储器(内存储器,简称内存)、计算机外部的存储器(外存储器,简称外存)
③主存和辅存: 一般来说,主存指的是内存;但是在一些专业性较强的场合,主存与内存还是有一定区别的。内存储存器还有其他形式。而外存指的是辅存,比如硬盘、U盘、光盘及软盘等。
④细说内存(主存): 内存又称主存,是CPU能直接寻址的存储空间,它的特点是存取速率快。内存是电脑中主要部件,它是相对于外存来说。内存一般采用半导体存储单元,包括:随机存储器(RAM)、只读存储器(ROM)和高级缓存(Cache)。
|内存种类 | 特点 |
|--|--|
| 随机存储器(RAM)| 高速存取,支持读写数据,读写时间相等,且与地址无关,但是断电后其中的数据会丢失。 |
只读存储器(ROM)| 断电后信息不丢失,如计算机启动用的BIOS芯片。存取速度很低,(较RAM而言)且不能改写。由于不能改写信息,不能升级,现已很少使用。
| 高级缓存(Cache)| 介于CPU与内存之间,常用有一级缓存(L1)、二级缓存(L2)、三级缓存(L3)(一般存在于Intel系列)。它的读写速度比内存还快,当CPU在内存中读取或写入数据时,数据会被保存在高级缓冲存储器中,当下次访问该数据时,CPU直接读取高级缓冲存储器,而不是更慢的内存。|
⑤细说外存(辅存): 外储存器是指除计算机内存及CPU缓存以外的储存器,此类储存器一般断电后仍然能保存数据。外存需要通过I/O系统与之交换数据,又称为辅助存储器。常见的外储存器有硬盘、软盘、光盘、U盘等。
(2)C程序运行的过程
①预处理:
预处理器(preprocessor)在源代码编译之前对其进行一些文本性质的操作。比如:删除注释、插入被#include
指令包含的文件的内容、定义和替换由#define
指令定义的符号,以及确定代码的部分内容是否应该根据一些条件编译指令进行编译。 ——《C和指针》
②编译:
由编译程序(Compiler)将用户源代码编译成cpu可执行的目标代码,产生了若干个目标模块(Object Module) 即若干程序段)。一般有这些工作:读取源程序(字符流),对之进行词法、语法和语义的分析,将高级语言指令转换为功能等效的汇编代码。
③汇编:
汇编实际上指把汇编语言代码翻译成目标机器指令的过程,生成目标文件。
④链接:
源程序经过编译、汇编后,可得到一组目标模块,再利用链接程序将这组目标模块链接,形成装入模块。根据链接时间的不同,可把链接分成如下三种:
1)静态链接(Static Linking):
在程序运行之前,先将各目标模块及它们所需的库函数,链接成一个完整的装配模块,以后不再拆开。我们把这种事先进行链接的方式称为静态链接方式。
2)装入时动态链接(Load-time Dynamic Linking):
这是指将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的链接方式。
3)运行时动态链接(Run-time Dynamic Linking):
这是指对某些目标模块的链接,是在程序执行中需要该(目标)模块时,才对它进行的链接。优点是便于修改和更新,便于实现对目标模块的共享。
⑤装入(内存):
由装入程序将目标模块装入内存中运行。装入有三种方式:
1)绝对装入(Absolute Loading Mode):
如果你是电子相关专业的,肯定在大学里捣鼓过单片机。单片机是没有操作系统的,所以每次写完代码,都需要借助工具把程序烧录进去,这样程序才能跑起来。在编译时,若知道程序将驻留在内存中的某个位置,则编译程序将产生绝对地址的目标代码。绝对装入程序按照装入模块中的地址,将程序和数据装入内存。由于程序中的逻辑地址和内存地址完全相同, 因此不需要对程序和数据的地址进行修改。绝对装入方式只适用于单道程序环境,另外,程序中所用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。而通常情况下在程序中采用的是符号地址,编译或汇编时在转为绝对地址。
2)可重定位装入(静态重定位)(Relocation Loading Mode):
在多道程序的运行环境下,我们并不能预知当程序并发执行的时候会放在内存的哪个地方。多个目标模块的起始地址通常都从0开始,其他的地址则是相对于0的相对地址,此时可采用重定位装入方式。根据内存的当时情况,将装入模块装入内存的适合位置。装入时对目标程序中指令和数据的修改过程称为重定位:地址变化通常是在装入时一次完成的,所以又称静态重定位。
*特点: 一个作业装入内存时,必须给它分配要求的全部内存空间,若没有足够的内存,则不能转入该作业。此外,作业一旦进入内存,整个运行期间就不能在内存中移动,也不能再申请内存空间。
3)动态运行时装入(动态重定位)(Dynamic Run-time Loading):
程序在内存种若发生移动,则需要采用动态的装入方式。装入程序把装入模块转入内存后,并不立即把装入模块种的相对地址转化为绝对地址,而是把这种地址转化推迟到程序真正正要执行时才进行。因此,装入内存后的所有地址均为相对地址,这种方式需要重定位寄存器的支持
特点: 可以把程序放在不连续的存储区中;在程序运行之前可以只装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。
⑥运行程序:
1) 程序必须载入内存中后。
2)程序的执行便开始。接着便调用main函数。
3)开始执行程序代码。这个时候程序将使用一个运行时堆栈(stack),存储函数的局部变量和返回
地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程
三、功能一:地址转化
在多道程序环境下,程序中的逻辑地址与内存中的物理地址,是不一致的,因此存储管理必须提供地址变化功能,才能把逻辑地址转化为相应的物理地址。
(1)为什么引入逻辑地址和物理地址?
参考up主视频:从0开始数
早期单进程的计算机我们直接采用绝对装入的方式把程序放到内存中(此时:逻辑地址和实际物理地址相同),但是随着不断地发展,我们引入了多进程,我们就需要让每个进程独立, 所以我们就不能用绝对地址。假设我们没有引入逻辑地址:进程1
执行JMP 20
(跳转到地址为20的指令)后,切换进程2
执行JMP 20
,这时我们发现进程2,就跳转到了进程1了。显然这不是我们所想得到的。故而引入了进程内部的相对地址也就是逻辑地址。程序指令中的地址不能是物理地址,而只能是相对地址。
(2)逻辑地址、物理地址?
①物理地址:
这里说的物理地址是内存中的内存单元实际地址。不是外部总线连接的其他电子元件的地址!内存中物理单元的集合,它是地址转化的最终地址,进程在运行时执行指令和访问数据,最后都要通过物理地址从内存中存取。当装入程序将可执行代码装入内存时,必须通过地址转化将逻辑地址转化为物理地址,这个过程称为重定位。
②逻辑地址(相对地址):
编译后,每个目标地址都从0号单元开始编址,这称为该目标模块的逻辑地址(相对地址)。例如:你在进行C语言指针编程中,能读取指针变量本身值(&操作),实际上这个值就是逻辑地址,它是相对于你当前进程数据段的地址,不和绝对物理地址相干。当链接程序将个模块链接成一个完整的可执行目标程序时,链接程序顺序依次按各个模块的相对地址构成统一的从0号单元开始编制的逻辑地址空间。用户程序和程序员只需要知道逻辑地址,而内存管理的具体机制则是完全透明的,只有操作系统编程人员才会涉及内存管理的具体机制。不同进程可以有相同的逻辑地址,因为这些相同的逻辑地址可以映射到主存的不同位置。从逻辑地址==>物理地址 交给操作系统去做。
三、功能二:存储保护
由上面我们引入了逻辑地址后,当进程的地址访问不是自己范围的地址的话,就会造成进程之间之间的干扰,这时候操作系统就发挥了它的功能:存储保护。
存储保护:内存分配前,需要保护操作系统不受用户进程的影响,同时保护用户进程不受其他用户进程的影响。(这种保护由硬件软件结合)
①重定位寄存器(基址寄存器)和界地址寄存器的硬件支持
通过这两种寄存器来实现保护。重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值。每个逻辑地址值必须小于界地址寄存器;内存管理机构动态地将逻辑地址与界地址寄存器进行比较,如果未发生地址越界,则加上重定位寄存器的值后映射成物理地址,再送交内存单元。每一个逻辑地址都需要与这两个寄存器进行核对,以保证操作系统和其他用户程序及数据不被该进程的运行所影响。注意一个用来加的,一个是用来比的
②上、下限寄存器
在CPU中设置一对下、上限寄存器,存放用户作业在主存中的下限和上限地址。每当CPU要访问主存,硬件自动将被访问的主存地址与这个两个限寄存器的内容进行比较,以判断是否越界。如果未越界,则按此地址访问主存,否则将产生程序中断——越界中断(存储保护中断)。
四、总结
这一节我们大概了解了一些知识背景,以及介绍了操作系统在内存管理中的两种功能:
①地址转化: 把逻辑地址转化为物理地址。
②存储保护: 多进程情况下,让每个作业在各自的空间运行,相互独立,不能互相干扰。
在后续博客中我们着重介绍操作系统在内存管理中的其他功能:内存空间分配与回收、内存空间扩充。