计算机操作系统(十七)内存管理
计算机操作系统(十七)内存管理
- 前言
- 一、内存的使用与程序重定位
- (一)内存是什么?
- (二)程序的重定位过程
- (三)总结:内存使用的核心问题
- 二、连续分区管理:早期的内存管理方案
- (一)什么是连续分区?
- (二)三种典型方案
- (三)连续分区的致命缺陷:内存碎片
- 三、分页管理:用"拆分成小块"解决碎片问题
- (一)核心思想:把内存和程序都切成小块
- (二)分页的优点
- (三)分页的问题
- 四、分段管理:从"逻辑模块"角度管理内存
- (一)为什么需要分段?
- (二)分段的核心概念
- (三)分段的优点
- (四)分段的缺点
- 五、段页式管理:集大成者
- (一)设计思想:分段+分页,取长补短
- (二)地址转换过程(稍微复杂,但更灵活)
- (三)优缺点
- (四)实际应用
前言
- 在上一篇博客中,我们深入探讨了进程同步,了解了进程间如何协调以避免冲突、有序执行。
- 进程运行离不开内存资源,因此,这一篇博客,我们将开启内存管理的学习之旅,探究操作系统是如何高效管理内存,为进程运行保驾护航的。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的操作系统博客专栏
https://blog.csdn.net/2402_83322742/category_12916780.html?spm=1001.2014.3001.5482
一、内存的使用与程序重定位
(一)内存是什么?
内存是计算机中用于临时存储数据和程序的硬件设备,就像我们日常办公时的"书桌"。当我们要运行一个程序(比如打开浏览器),计算机需要先把程序从硬盘(相当于"文件柜")复制到内存这个"书桌"上,CPU才能快速读取并执行。
(二)程序的重定位过程
-
程序的三种地址形态
- 逻辑地址:程序员写代码时用的"虚拟地址",比如在C语言中定义
int a=10;
,编译器会给变量a
分配一个逻辑地址(例如0x1000),这个地址不考虑实际内存位置。 - 相对地址:经过汇编或编译后生成的"相对起始地址"。比如一个程序模块的相对地址从0开始,内部函数调用使用相对地址(如调用偏移量100的函数)。
- 物理地址:内存中真实的硬件地址,就像每个内存单元的"门牌号"(例如0x80000010)。
- 逻辑地址:程序员写代码时用的"虚拟地址",比如在C语言中定义
-
为什么需要重定位?
当程序被装入内存时,它在内存中的起始位置是不确定的。比如同一个程序第一次从内存地址0x1000开始存放,第二次可能从0x5000开始。这时候程序内部的逻辑地址必须转换成对应的物理地址,否则CPU会找不到正确的数据,就像快递地址写错会导致包裹送错地方。 -
两种重定位方式
- 静态重定位:在程序装入内存时一次性完成地址转换。就像搬家前把所有家具的位置在图纸上标好,搬家时直接按图纸摆放,之后不再改变。优点是简单,缺点是程序一旦装入就不能移动位置。
- 动态重定位:程序运行时通过硬件地址转换机构(如基址寄存器)实时转换地址。就像随身携带一个"地址翻译器",走到哪里都能把逻辑地址翻译成当前位置的物理地址。优点是程序可以在内存中移动(比如内存紧凑时),缺点是需要额外的硬件支持。
(三)总结:内存使用的核心问题
程序要在内存中运行,必须解决"地址转换"的问题,而重定位就是连接逻辑世界(程序员视角)和物理世界(硬件视角)的桥梁。
二、连续分区管理:早期的内存管理方案
(一)什么是连续分区?
- 把内存划分为若干个连续的区域,每个区域分配给一个程序使用,就像把一块大蛋糕切成若干块,每块给一个人吃。
- 早期的操作系统(如DOS)常用这种方式。
(二)三种典型方案
-
单一连续分区(最简单的方案)
- 内存分为两部分:一部分给操作系统(比如Windows的内核),剩下的全部给一个应用程序。
- 缺点:一次只能运行一个程序(想想看,你不能同时打开微信和浏览器),内存利用率极低。
-
固定分区(稍微进步一点)
- 提前把内存划分为大小固定的几个分区(比如1MB、2MB、4MB),每个分区可以存放一个程序。
- 问题:如果程序大小超过分区大小,无法装入;如果程序太小,分区剩余空间浪费(比如一个500KB的程序装入1MB的分区,浪费500KB)。
-
动态分区(按需分配)
- 不再提前划分分区,而是根据程序需要动态划分。比如程序需要3MB内存,就从空闲内存中切出3MB的连续空间。
- 关键问题:如何高效分配和回收空间?
- 分配算法:
- 首次适应:从内存起始位置开始找,第一个足够大的空闲块就分配,简单但可能留下小碎片。
- 最佳适应:找最接近程序大小的空闲块,看似合理,却容易产生大量微小碎片(比如把大空闲块切成刚好够用的小块,剩下的小碎片难以利用)。
- 回收问题:当程序运行结束释放内存时,如果相邻的空闲块,需要合并成一个大的空闲块,否则会形成不连续的碎片。
- 分配算法:
(三)连续分区的致命缺陷:内存碎片
无论是固定分区还是动态分区,都会面临"碎片问题"。比如内存中有多个小的空闲块,但合起来不够一个程序使用(就像钱包里有很多零钱,但凑不出一张整钞)。为了解决这个问题,操作系统不得不定期进行"内存紧凑"(把正在运行的程序移动到连续的区域,合并空闲块),但这会消耗大量CPU资源。
三、分页管理:用"拆分成小块"解决碎片问题
(一)核心思想:把内存和程序都切成小块
-
页与页框
- 把程序逻辑地址空间划分为大小相等的"页"(Page,比如4KB大小)。
- 把物理内存划分为同样大小的"页框"(Page Frame,也叫页帧)。
- 程序的每个页可以装入任意一个页框,不需要连续,就像把一本书拆分成若干章节(页),每个章节可以放在不同的书架格子(页框)里,只要知道每个章节放在哪个格子,就能快速找到。
-
页表:记录"页"的位置
- 每个程序有一张"页表",记录逻辑页号到物理页框号的映射关系。比如逻辑页0对应物理页框5,逻辑页1对应物理页框3。
- 地址转换过程:当程序访问逻辑地址(由页号+页内偏移组成),CPU通过页表找到对应的页框号,再加上页内偏移,得到物理地址。例如:页大小4KB(12位),逻辑地址0x1234(二进制0001 0010 0011 0100),前4位(0001)是页号,后12位(0010 0011 0100)是页内偏移。通过页表查到页号1对应的页框号是3(二进制0011),物理地址就是0011 0010 0011 0100(0x3234)。
(二)分页的优点
- 几乎消除外部碎片:程序的页可以分散存储,只要有足够的页框就能装入,不会因为空闲块不连续而无法分配。
- 内存利用率高:页的大小固定(通常4KB-8KB),每个程序最后一个页即使没装满,浪费的空间也很小(最多一个页的大小),这叫"内部碎片",比连续分区的碎片问题好很多。
(三)分页的问题
- 页表占用内存:每个程序都需要页表,如果页表很大(比如64位系统),可能需要多级页表(比如二级页表、三级页表)来减少内存占用。
- 程序员无感知:分页是操作系统底层的机制,程序员不需要关心,所有地址转换由硬件和操作系统自动完成。
四、分段管理:从"逻辑模块"角度管理内存
(一)为什么需要分段?
分页解决了内存碎片问题,但它是从"物理内存划分"的角度设计的,而程序员写程序时更习惯按逻辑模块划分(比如代码段、数据段、堆栈段)。比如一个C程序包含main函数(代码段)、全局变量(数据段)、函数调用栈(堆栈段),分段管理就是把这些逻辑模块分别装入内存,每个段可以独立增长和共享。
(二)分段的核心概念
- 段:每个程序由若干个段组成,每个段有自己的名称(如代码段
.text
、数据段.data
)和长度。比如代码段可能有10KB,数据段可能有5KB。 - 段表:记录每个段的起始物理地址和长度。当程序访问逻辑地址(段号+段内偏移),首先检查段内偏移是否超过段长度(防止越界访问,比如数组下标越界),然后用段号找到段的起始地址,加上偏移得到物理地址。
(三)分段的优点
- 符合程序逻辑结构:程序员可以直观地理解内存布局,比如调试时知道代码段在哪个区域,数据段在哪个区域。
- 支持段的共享与保护:多个程序可以共享同一个代码段(比如共享C语言标准库),每个段可以设置访问权限(代码段只读,数据段可读写)。
(四)分段的缺点
- 外部碎片问题回归:每个段需要连续的内存空间,段与段之间可能产生碎片(类似动态分区管理的问题)。
- 段大小不固定:大段可能难以分配,小段可能浪费空间(但比连续分区好,因为程序可以分成多个小段)。
五、段页式管理:集大成者
(一)设计思想:分段+分页,取长补短
- 先分段,再分页:每个段被划分为若干个页,结合分段的逻辑模块化和分页的内存高效利用。
- 比如代码段分成3个页,数据段分成2个页,每个页装入页框,不需要连续。
- 地址结构:段号+段内页号+页内偏移。通过段表找到段对应的页目录表,再通过页表找到页框号,最后得到物理地址。
(二)地址转换过程(稍微复杂,但更灵活)
- 程序访问逻辑地址(段号S,段内逻辑地址A)。
- 通过段表找到该段的页目录表起始地址。
- 段内逻辑地址A分为页号P和页内偏移D。
- 通过页目录表和页表找到页框号F。
- 物理地址 = F×页大小 + D。
(三)优缺点
- 优点:
- 既有分段的逻辑清晰(支持模块划分、共享、保护),又有分页的内存高效(消除外部碎片,内部碎片少)。
- 适合大型程序和多任务系统(如Windows、Linux)。
- 缺点:
- 地址转换需要多次访问内存(段表+页表),为了加速,通常使用"快表"(TLB,高速缓存)来缓存最近访问的段页信息。
- 管理复杂度最高,需要维护段表和页表两级结构。
(四)实际应用
现代操作系统(如x86架构的Linux、Windows)普遍采用段页式管理,但为了简化,有时会让段的作用弱化(比如默认段号为0,只使用分页),但底层机制仍支持分段与分页的结合。
以上就是对本次关于操作系统博客内容的总结,后续我们将深入探讨操作系统更多知识。
我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343
我的操作系统博客专栏
https://blog.csdn.net/2402_83322742/category_12916780.html?spm=1001.2014.3001.5482
非常感谢您的阅读,喜欢的话记得三连哦 |