03.内存管理
# 01.操作系统内存管理
# 0、概述
内存管理是计算机操作系统中的核心功能之一
负责有效地分配和管理系统的物理内存资源,确保不同进程之间能合理、安全地使用内存
内存分配:为每个进程分配足够的内存
地址映射:通过虚拟内存和物理内存之间的映射,提高内存利用效率
保护和隔离:防止进程非法访问其他进程的内存
内存回收:及时释放不再使用的内存
虚拟内存的调度方式有
分页式、段式、段页式 3种(大部分操作系统使分页式
)
# 1、虚拟内存
① 虚拟内存是什么?
虚拟内存是一种使计算机系统可以使用比实际物理内存更大的地址空间的技术
它通过将程序的地址空间映射到物理内存,允许不必将程序的每一页都加载到内存中就能运行
这使得系统可以运行超出物理内存容量的应用程序
② 虚拟内存的工作原理
- 操作系统将内存抽象为一个地址空间,每个程序拥有独立的地址空间
- 地址空间分割为多个页,
每一页可能映射到物理内存的某个页框,但不一定是连续的
- 当程序
访问的页不在内存中时
,会发生缺页中断,操作系统将缺失的页从磁盘调入内存
③ 虚拟内存优点
更大的地址空间:允许程序使用比物理内存更大的虚拟地址空间
进程隔离:每个进程有独立的地址空间,防止相互干扰
按需调入:只需将当前需要的页加载到内存,提高内存利用率
# 2、分页 地址映射
# 1)分页原理
① 分页是什么?
分页是将进程的
逻辑地址空间
划分为固定大小的页 (Page)物理内存
同样被划分为等大小的 页框 (Page Frame)
并通过内存管理单元 (MMU) 实现
虚拟地址到物理地址的映射
MMU 通过页表 (Page Table) 管理页和页框的映射
② 页表工作原理
一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量
页号通过页表查找到对应的
页框号
,再加上页内偏移生成物理地址
示例:
- 假设虚拟地址为
0010 000000000100
,其中前4位
表示页号2
- 系统从页表中读取到该页对应的页框为
110
,然后组合成物理地址110 000000000100
- 假设虚拟地址为
页表中的存在位 (P) 标识页面是否在内存中,若不在则触发缺页中断
# 2)分页访问
- 访问分页系统中内存数据需要两次的内存访问
- 一次是从内存中访问页表,从中找到指定的物理块号,加上页内偏移得到实际物理地址
- 第二次就是根据第一次得到的物理地址访问内存取出数据
工作原理图
# 3)页面置换算法
- 当
内存已满时
,如果需要调入新的页面
,操作系统需要决定替换哪个页面
- 页面置换算法决定了如何选择需要被换出的页面,以减少缺页中断的频率
- 常见页面置换算法如下
最佳页面置换算法 (OPT)
选择未来最久不会被访问的页面进行置换
- 这是理论上的最优解,但在实际应用中无法预测未来的页面访问顺序
最近最久未使用 (LRU)
- 将最近最久未使用的页面换出,依据页面的历史使用记录来预测未来的使用
- 实现
LRU 需要维护一个链表,每次访问时将页面移至链表表头
,这会带来较高的开销
最近未使用 (NRU)
- 页面有两个状态位:R(是否被访问)和 M(是否被修改)
- 操作系统优先
选择 R=0、M=0 的页面进行置换
先进先出 (FIFO)
- 最早进入内存的页面将被最先替换
- FIFO容易导致频繁访问的页面被错误置换,增加缺页率
第二次机会算法
- 改进的 FIFO
- 增加 R 位标志,若 R=1(页面最近被访问),则跳过该页面,给它“第二次机会”
时钟算法 (Clock)
- 是第二次机会算法的优化版本,使用环形链表和一个指针指向最老的页面
- 当替换页面时,检查 R 位并做出相应决策
# 3、分段
分页是为了提高内存利用率
而分段是为了满足程序员在编写代码的时候的一些逻辑需求 (比如数据共享,数据保护,动态链接等)
分段内存管理当中,地址是二维的,一维是
段号
,二维是段内地址
;其中每个段的长度是不一样的,而且每个段内部都是从0开始编址的
由于分段管理中,每个
段内部是连续内存分配,但是段和段之间是离散分配的
因此也存在一个
逻辑地址到物理地址的映射关系,相应的就是段表机制
、
# 4、段页式存储管理
- 段页式系统结合了分页和分段的优点
- 首先将程序划分为段,每个段又细分为多个页
- 段页式系统既支持分段的逻辑分割,又支持分页的虚拟内存功能
# 5、分页与分段的比较
- 对程序员的透明性:分页对程序员透明,分段则需要程序员显式划分段
- 地址空间维度:分页是一维地址空间,分段是二维地址空间
- 大小调整:页大小固定,段大小可以动态调整
- 设计目的:分页主要为实现虚拟内存,分段用于逻辑上的独立分割和数据共享
# 02.常见问题
# 1、什么是分页?
分页是一种内存管理技术,将内存分割成大小相等且固定的块,这些块被称为页,是进程地址空间的基本单位
分页系统通过页表来映射虚拟地址和物理地址
在分页系统中,访问内存通常需要两次内存访问
第一次:访问页表,找到对应的物理块号,并加上偏移量生成物理地址、
第二次:使用生成的物理地址从内存中读取数据、
# 2、什么是分段?
分段是另一种内存管理方式,主要用于满足程序逻辑上的需求(如数据共享、数据保护、动态链接)
在分段内存管理中,地址是二维的,分为段号和段内偏移
段号:指示内存段的位置、
段内地址:
- 表示段内的具体位置
- 每个段的大小可变,段和段之间是离散分布的,但段内地址是连续的、
分段系统同样需要一个段表来进行段号到物理地址的映射、
# 3、分页和分段有什区别?
透明性:分页对程序员是透明的,分段需要程序员显式划分、
地址空间维度:分页是一维地址空间,分段是二维地址空间、
大小变化:页的大小固定,段的大小可以动态改变、
用途:
- 分页主要用于实现虚拟内存,获得更大的地址空间;
- 分段则用于逻辑划分,便于数据共享和保护、
# 4、什么是交换空间?
交换空间(Swap Space)是系统在硬盘上预留的一块空间,用于存储物理内存中的一些页,以释放内存空间
当物理内存不足时,操作系统会将不常用的内存页交换到硬盘的交换空间中
这一过程称为交换(Swapping)、
作用
- 当物理内存不足时,系统可以将不常用的页交换到硬盘,释放内存资源、
- 某些初始化后不再需要的页也可以被交换出去、
物理内存和交换空间的总容量是系统可用的虚拟内存总量、
# 5、页面替换算法有哪些?
- 在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中
- 此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间
- 最优页面替换算法(Optimal Algorithm):
- 理论上的最佳算法,它总是置换未来最晚使用的页面
- 虽然无法实际实现,但可以作为其他算法的性能标准、
- NRU(Not Recently Used)算法:
- 根据页的使用情况,将页面分为四类,并从编号最小的类别中随机选择页面置换
- 该算法简单易行,但性能一般、
- FIFO(First In, First Out)算法:
- 按照页面进入内存的顺序进行替换、容易造成频繁使用的页面被替换,性能较差、
- 第二次机会算法:
- 在FIFO基础上,检查即将替换的页面是否被最近访问过
- 如果是,则给它第二次机会,避免频繁访问的页面被替换、
- 时钟算法(Clock Algorithm):
- 时钟算法是第二次机会算法的一种实现形式
- 它会以环形队列的方式遍历页面,检查每个页面的访问情况、
- LRU(Least Recently Used)算法:
- 替换最近最少使用的页面
- 虽然理论上性能很好,但由于需要记录每个页面的使用顺序,实际实现较为复杂,通常需要特殊硬件支持、
- NFU(Not Frequently Used)算法:
- 简单的近似LRU算法,按页面的访问频率替换页面,性能较为一般、
- 老化算法:
- 类似于LRU算法,但通过位操作实现,性能更好且较易实现、
- WSClock算法:
- 工作集算法的变种,结合了时钟算法和工作集模型,性能良好且易于实现、
最佳实践:老化算法和WSClock算法结合了较好的性能和实现效率,常用于实际系统中、
# 6、为什么虚拟地址空间切换会比较耗时?
当
进程切换时
,虚拟地址空间也需要切换
- 而这主要涉及页表(Page Table)
- ***TLB(Translation Lookaside Buffer)***的操作
每个进程有自己的虚拟地址空间,虚拟地址需要通过页表转换为物理地址
为了提高地址转换效率,操作系统使用 TLB 作为缓存,保存最近使用的地址映射
然而,进程切换时,页表也要切换,导致 TLB 中缓存的旧映射失效,这就是所谓的 TLB flush
TLB 失效后,系统需要重新查询页表,从而增加了地址转换的延迟
这也是为什么进程切换相比线程切换更为耗时的原因
线程切换不涉及地址空间的变化,因此不需要切换页表或清空 TLB,效率较高