重生之我是操作系统(七)----内存管理(下)

存储隔离

存储隔离,又称为存储保护。确保不同进程、用户空间与内核空间之间的内存互不干扰,防止非法访问或数据破坏。

在操作性系统早期发展的阶段。经常使用两种寄存器来实现隔离。

  1. 上下限寄存器
    在CPU中设置一对上下限寄存器,存放进程的上下限地址,当指令要访问某个地址时,CPU检查是否越界
  2. 重定位寄存器&界地址寄存器
    重定位寄存器存放的是进程的起始物理地址,界地址寄存器存放的是进程的最大逻辑地址。

这些寄存器用于非分页 / 非分段的连续内存分配(如固定分区、动态分区),通过基址 + 限长的方式隔离进程地址空间

它们存在很大的局限性,保护粒度较粗(基于整个程序地址空间,无法细粒度到页或段)。

因此,随着页/段的,线程等现代操作系统概念的普及。基本上已经被淘汰,取而代之的是更加复杂的现代内存管理,也就是上一篇文中讲到的,页/段/段页机制。

  1. 虚拟地址通过 页目录基址寄存器(CR3)+ 页表 逐级映射到物理地址,取代 "重定位寄存器 + 逻辑地址" 的简单加法。
  2. 支持虚拟内存、非连续内存分配,解决早期寄存器的碎片问题。
  3. 页表项包含 访问权限位(如用户态不可读、禁止执行),MMU 在地址转换时自动检查权限,发现越界或非法访问则触发异常(如缺页中断、权限错误)。

x86架构的段描述符仍包含 段基址 和 段界限,可用于实现类似上下限寄存器的功能(如隔离用户空间和内核空间),但分段在现代系统中更多是兼容性设计,核心保护依赖分页。

高效通信

在文件读写中,文件的数据是离散存储在硬盘中的。读写文件需要如下几步:

  1. open系统调用,打开文件
  2. seed系统调用,将读写指针移动到某个位置
  3. read系统调用,从读写指针所指位置读取数据
  4. rite系统调用,从读写指针所指位置写入数据

这里的操作就很繁琐,程序员需要自己移动指针,然后读写数据。

按照现在的说法来说,什么都要自己亲历亲为(面向过程),一点都不OOP(面向对象)。

因此,内存映射文件(Memory-Mapped Files)就应运而生。

通过将磁盘文件的内容直接映射到进程的虚拟地址空间,使进程可以像访问内存一样读写文件数据,无需显式执行传统的输入输出(I/O)操作(如read/write)。

利用内存映射文件,操作步骤就简化为:

  1. open系统调用,打开文件
  2. mmap建立映射
    操作系统在进程的虚拟地址空间中分配一段区域,并将其与磁盘文件的某个区域(如整个文件或部分片段)建立映射关系
  3. 读写文件
    对映射内存的修改会被操作系统异步或同步地写回磁盘文件,无需用户手动调用write函数
    当进程访问映射区域的内存地址时,若对应的数据尚未加载到物理内存,系统通过缺页中断自动从磁盘文件读取数据并填充到物理内存

内存映射文件实现文件共享

这样,多个进程可以映射同一个文件,实现共享。

优点如下:

  1. 高效I/O
    避免传统 I/O 的用户空间与内核空间数据拷贝(如read需先将数据读入内核缓冲区,再复制到用户空间),直接通过内存访问操作文件,大幅提升大文件读写性能。
  2. 内存占用低
    文件内容按需加载(仅访问的部分被读取到内存),节省物理内存占用,方便处理大文件。
  3. 跨进程数据共享
    数据修改会实时反映到所有映射该文件的进程中

在此基础上,还演化出不关联任何磁盘文件,直接分配一段可共享的内存区域,实现进程间的内存共享。

常作为临时数据缓冲区